बैश बिल्ट-इन के साथ `एग्जीक्यूटिव` चलाना


9

मैंने एक शेल फ़ंक्शन को परिभाषित किया (चलो इसे कॉल करें clock), जिसे मैं timeफ़ंक्शन के समान, दूसरे कमांड के लिए एक आवरण के रूप में उपयोग करना चाहता हूं clock ls -R

मेरा शेल फ़ंक्शन कुछ कार्य करता है और फिर समाप्त होता है exec "$@"

मैं इस फ़ंक्शन को शेल बिल्ट-इन के साथ भी काम करना चाहता हूं, जैसे कि बिल्ट-इन clock time ls -Rका परिणाम आउटपुट करना चाहिए time, और /usr/bin/timeनिष्पादन योग्य नहीं । लेकिन execहमेशा इसके बजाय कमांड चलाना समाप्त करता है।

मैं अपने बैश फ़ंक्शन को एक रैपर के रूप में कैसे काम कर सकता हूं जो शेल बिल्ट-इन को तर्कों के रूप में भी स्वीकार करता है?

संपादित करें : मैंने अभी सीखा कि timeबैश बिल्ट-इन नहीं है, बल्कि पाइपलाइनों से संबंधित एक विशेष आरक्षित शब्द है । मैं अभी भी बिल्ट-इन के लिए एक समाधान में दिलचस्पी रखता हूं, भले ही इसके साथ काम न करें time, लेकिन एक अधिक सामान्य समाधान भी बेहतर होगा।


आपको स्पष्ट रूप से एक शेल का उपयोग करने की आवश्यकता है exec bash -c \' "$@" \'। जब तक पहले पैरामीटर में आपकी कमांड शेल स्क्रिप्ट के रूप में मान्यता प्राप्त है, तब इसे सीधे चलाने के लिए द्विआधारी के रूप में व्याख्या की जाएगी। वैकल्पिक रूप से, और अधिक सरल रूप से, बस अपने मूल शेल से याद execकरें और कॉल करें "@"
AFH

जवाबों:


9

आपने बैश फ़ंक्शन को परिभाषित किया है। तो आप उस फ़ंक्शन को लागू करते समय पहले से ही एक bash शेल में हैं। तो यह कार्य तब जैसा दिखता है:

clock(){
  echo "do something"
  $@
}

उस समारोह को बैश बिल्डरों, विशेष आरक्षित शब्दों, आदेशों, अन्य परिभाषित कार्यों के साथ लागू किया जा सकता है:

एक उपनाम:

$ clock type ls
do something
ls is aliased to `ls --color=auto'

एक बैश बिलिन:

$ clock type type
do something
type is a shell builtin

एक अन्य समारोह:

$ clock clock
do something
do something

एक निष्पादन योग्य:

$ clock date
do something
Tue Apr 21 14:11:59 CEST 2015

इस मामले में, क्या रनिंग $@और exec $@, के बीच कोई अंतर है , अगर मुझे पता है कि मैं एक वास्तविक कमांड चला रहा हूं?
एओल

3
जब आप उपयोग करते हैं exec, तो कमांड शेल को बदल देती है। इसलिए वहाँ कोई बिलियन, उपनाम, विशेष आरक्षित शब्द, परिभाषित शब्द नहीं हैं, क्योंकि निष्पादन योग्य को सिस्टम कॉल के माध्यम से निष्पादित किया जाता है execve()। वह syscall एक निष्पादन योग्य फ़ाइल की अपेक्षा करता है।
अराजकता

लेकिन एक बाहरी पर्यवेक्षक के दृष्टिकोण से, क्या उन्हें अभी भी भेद करना संभव है, जैसे exec $0कि एक ही प्रक्रिया है, जबकि $@अभी भी दो हैं।
12

4
हां, $@माता-पिता के रूप में रनिंग शेल और चाइल्ड प्रोसेस के रूप में कमांड है। लेकिन जब आप बिल्डिंस, एलियास आदि का उपयोग करना चाहते हैं, तो आपको शेल को संरक्षित करना होगा। या एक नई शुरुआत करें।
अराजकता

4

शेल बिलिन या शेल कीवर्ड लॉन्च करने का एकमात्र तरीका एक नया शेल लॉन्च करना है, क्योंकि "दिए गए कमांड के साथ शेल को बदलता है"। आपको अपनी अंतिम पंक्ति को प्रतिस्थापित करना चाहिए:

IFS=' '; exec bash -c "$*"

यह निर्मित और आरक्षित शब्दों दोनों के साथ काम करता है; सिद्धांत समान है।


3

यदि रैपर को दिए गए कमांड से पहले कोड डालने की आवश्यकता होती है , तो एक उपनाम काम करेगा क्योंकि वे बहुत प्रारंभिक चरण में विस्तारित होते हैं:

alias clock="do this; do that;"

उपनाम लगभग शब्द के स्थान पर वस्तुतः डाला जाता है, इसलिए अनुगामी ;महत्वपूर्ण है - यह clock time fooविस्तार करता है do this; do that; time foo

आप जादू उपनाम बनाने के लिए इसका दुरुपयोग कर सकते हैं जो यहां तक ​​कि बाईपास उद्धरण भी है।


कमांड के बाद कोड डालने के लिए , आप "DEBUG" हुक का उपयोग कर सकते हैं।

shopt -s extdebug
trap "<code>" DEBUG

विशेष रूप से:

shopt -s extdebug
trap 'if [[ $BASH_COMMAND == "clock "* ]]; then
          eval "${BASH_COMMAND#clock }"; echo "Whee!"; false
      fi' DEBUG

हुक अभी भी कमांड से पहले चलता है , लेकिन जब वह वापस लौटता है, तो falseयह मारपीट को रद्द करने के लिए कहता है (क्योंकि हुक ने पहले ही इसे निष्कासित कर दिया था)।

एक अन्य उदाहरण के रूप में, आप इसका उपयोग उपनाम के command pleaseलिए कर सकते हैं sudo command:

trap 'case $BASH_COMMAND in *\ please) eval sudo ${BASH_COMMAND% *}; false; esac' DEBUG

1

एकमात्र समाधान जो मैं अब तक आ सकता था, यह जानने के लिए कि क्या पहला तर्क एक कमांड, बिल्ट-इन या कीवर्ड है, और अंतिम मामले में विफल होने के लिए एक केस विश्लेषण करना होगा:

#!/bin/bash

case $(type -t "$1") in
  file)
    # do stuff
    exec "$@"
    ;;
  builtin)
    # do stuff
    builtin "$@"
    ;;
  keyword)
    >&2 echo "error: cannot handle keywords: $1"
    exit 1
    ;;
  *)
    >&2 echo "error: unknown type: $1"
    exit 1
    ;;
esac

timeहालांकि, यह संभाल नहीं करता है , इसलिए एक बेहतर (और अधिक संक्षिप्त) समाधान हो सकता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.