क्या $ BASH_COMMAND को निकालना सुरक्षित है?


11

मैं एक शेल स्क्रिप्ट पर काम कर रहा हूं, जो चर से एक जटिल कमांड का निर्माण करता है, उदाहरण के लिए इस तरह (एक तकनीक के साथ जो मैंने बीएफएस FAQ से सीखा है ):

#!/bin/bash

SOME_ARG="abc"
ANOTHER_ARG="def"

some_complex_command \
  ${SOME_ARG:+--do-something "$SOME_ARG"} \
  ${ANOTHER_ARG:+--with "$ANOTHER_ARG"}

यह स्क्रिप्ट गतिशील पैरामीटर जोड़ देता है --do-something "$SOME_ARG"और --with "$ANOTHER_ARG"करने के लिए some_complex_commandकरता है, तो इन चरों परिभाषित कर रहे हैं। अभी तक यह ठीक चल रहा है।

लेकिन अब मैं कमांड को प्रिंट या लॉग इन करने में सक्षम होना चाहता हूं, जब मैं इसे चला रहा हूं, उदाहरण के लिए जब मेरी स्क्रिप्ट डिबग मोड में चलती है। इसलिए जब मेरी स्क्रिप्ट चलती है some_complex_command --do-something abc --with def, तो मैं भी चाहता हूं कि यह कमांड एक वैरिएबल के अंदर हो ताकि मैं इसे syslog में लॉग कर सकूं।

बैश एफएक्यू इस उद्देश्य के लिए जाल और चर (उदाहरण के लिए डिबगिंग उद्देश्यों के लिए) का उपयोगDEBUG$BASH_COMMAND करने की तकनीक प्रदर्शित करता है । मैंने कोशिश की है कि निम्नलिखित कोड के साथ:

#!/bin/bash

ARG="test string"

trap 'COMMAND="$BASH_COMMAND"; trap - DEBUG' DEBUG
echo "$ARG"

echo "Command was: ${COMMAND}"

यह काम करता है, लेकिन यह कमांड में चर का विस्तार नहीं करता है:

host ~ # ./test.sh
test string
Command was: echo "$ARG"

मुझे लगता है कि मुझे विस्तार करने के लिए eval का उपयोग echo "$ARG"करना होगा echo test string(कम से कम मुझे evalअभी तक कोई रास्ता नहीं मिला है )। निम्नलिखित काम करता है:

eval echo "Command was: ${COMMAND}"

यह निम्नलिखित उत्पादन का उत्पादन करता है:

host ~ # ./test.sh
test string
Command was: echo "$ARG"
Command was: echo test string

लेकिन मैं वास्तव में निश्चित नहीं हूं अगर मैं evalइस तरह से सुरक्षित रूप से उपयोग कर सकता हूं । मैंने कुछ चीजों के दोहन की असफल कोशिश की है:

#!/bin/bash

ARG="test string; touch /x"
DANGER='$(touch /y; cat /etc/shadow)'

trap 'COMMAND="$BASH_COMMAND"; trap - DEBUG' DEBUG
echo "$ARG" $DANGER

echo "Command was: ${COMMAND}"
eval echo "Command was: ${COMMAND}"

ऐसा लगता है कि इसे अच्छी तरह से संभालना है, लेकिन अगर कोई व्यक्ति किसी मुद्दे को देखता है तो मैं उत्सुक हूं।


यह वही है जो मैं एक sudo आवरण में वर्षों से उपयोग कर रहा हूं, मैंने कभी किसी मुद्दे पर ध्यान नहीं दिया।
w00t

जवाबों:


7

एक संभावना एक आवरण समारोह बनाने की है जो एक ही समय में कमांड को प्रिंट करेगा और इसे निष्पादित करेगा, इस प्रकार है:

debug() {
    # This function prints (to stdout) its arguments and executes them
    local args=() idx=0 IFS=' ' c
    for c; do printf -v args[idx++] '%q' "$c"; done
    printf "%s\n" "${args[*]}"
    # Execute!
    "$@"
}

ताकि आपकी स्क्रिप्ट में आप यह कर सकें:

debug echo "$ARG"

जाल के साथ बेला करने की कोई जरूरत नहीं है। दोष यह है कि यह debugआपके कोड पर सभी कीवर्ड जोड़ता है (लेकिन यह ठीक होना चाहिए, इस तरह के सामान, जैसे कि आरोही, आदि के लिए यह आम है)।

तुम भी एक वैश्विक चर जोड़ सकते हैं DEBUGऔर इस debugतरह समारोह को संशोधित कर सकते हैं :

debug() {
    # This function prints (to stdout) its arguments if DEBUG is non-null
    # and executes them
    if [[ $DEBUG ]]; then
        local args=() idx=0 IFS=' ' c
        for c; do printf -v args[idx++] '%q' "$c"; done
        printf "%s\n" "${args[*]}"
    fi
    # Execute!
    "$@"
}

तब आप अपनी स्क्रिप्ट को इस प्रकार कह सकते हैं:

$ DEBUG=yes ./myscript

या

$ DEBUG= ./myscript

या केवल

$ ./myscript

निर्भर करता है कि आप डिबग जानकारी चाहते हैं या नहीं।

मैंने DEBUGचर को बड़ा किया क्योंकि इसे पर्यावरण चर के रूप में माना जाना चाहिए। DEBUGएक तुच्छ और सामान्य नाम है, इसलिए यह अन्य आदेशों के साथ टकरा सकता है। शायद यह फोन GNIOURF_DEBUGया MARTIN_VON_WITTICH_DEBUGया UNICORN_DEBUGअगर आप सपनों की तरह (और तो आप शायद टट्टू की तरह भी)।

ध्यान दें। में debugसमारोह, मैं ध्यान के साथ प्रत्येक तर्क स्वरूपित printf '%q'ताकि उत्पादन सही ढंग से छोड़ दिया जाएगा और इसलिए उद्धृत के रूप में एक सीधा प्रति के साथ पुन: प्रयोज्य शब्दशः हो सकता है और पेस्ट करने के लिए। यह आपको यह भी दिखाएगा कि शेल ने क्या देखा था जैसा कि आप प्रत्येक तर्क (रिक्त स्थान या अन्य अजीब प्रतीकों के मामले में) का पता लगाने में सक्षम होंगे। यह फ़ंक्शन अनावश्यक उपखंडों से बचने के लिए -vस्विच के साथ प्रत्यक्ष असाइनमेंट का भी उपयोग करता है printf


1
फ़ंक्शन बहुत अच्छा काम करता है, लेकिन दुर्भाग्य से मेरी कमान में पुनर्निर्देशन और "पृष्ठभूमि में बहाना" नियंत्रण ऑपरेटर शामिल हैं &। मुझे इसे काम पर लाने के लिए फंक्शन में जाना पड़ा - बहुत अच्छा नहीं, लेकिन मुझे नहीं लगता कि कोई बेहतर तरीका है। लेकिन अब और नहीं eval, इसलिए मुझे वह मिल गया है जो मेरे लिए है, जो अच्छा है :)
मार्टिन वॉन विटिच

5

eval "$BASH_COMMAND" कमांड चलाता है।

printf '%s\n' "$BASH_COMMAND" सटीक निर्दिष्ट कमांड प्रिंट करता है, साथ ही एक नई पंक्ति।

यदि कमांड में वैरिएबल होते हैं (जैसे कि यदि यह कुछ ऐसा है cat "$foo"), तो कमांड प्रिंट करके वेरिएबल टेक्स्ट को प्रिंट करता है। कमांड को निष्पादित किए बिना चर के मूल्य को प्रिंट करना असंभव है - जैसे आदेशों के बारे में सोचें variable=$(some_function) other_variable=$variable

शेल स्क्रिप्ट को निष्पादित करने से ट्रेस प्राप्त करने का सबसे सरल तरीका यह है कि xtraceशेल के अंदर स्क्रिप्ट को bash -x /path/to/scriptइनवॉइस के रूप में चलाकर या खोल विकल्प सेट करें set -x। ट्रेस मानक त्रुटि पर मुद्रित होता है।


1
मुझे पता है xtrace, लेकिन इससे मुझे बहुत अधिक नियंत्रण नहीं मिलता है। मैंने "सेट -x; ...; सेट + x" की कोशिश की, लेकिन: 1) xtrace को निष्क्रिय करने के लिए "सेट + x" कमांड 2 भी मुद्रित होता है) मैं आउटपुट को उपसर्ग नहीं कर सकता हूं जैसे टाइमस्टैम्प 3 के साथ) मैं कर सकता हूं 'इसे लॉग इन न करें।
मार्टिन वॉन विटिच

2
"कमांड को निष्पादित किए बिना चर के मूल्य को प्रिंट करना असंभव है" - अच्छा उदाहरण, मैंने इस तरह के मामले पर विचार नहीं किया था। यह अच्छा होगा हालांकि अगर बैश के पास एक अतिरिक्त चर था, BASH_COMMANDजिसमें विस्तारित कमांड शामिल है, क्योंकि कुछ बिंदु पर इसे वैसे भी कमांड पर चर विस्तार करना पड़ता है जब इसे निष्पादित कर रहा है :)
मार्टिन वॉन विटिच
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.