बैश में स्ट्रिंग को सम्‍मिलित करके कमांड बनाएँ


14

मेरे पास एक बैश स्क्रिप्ट है जो एक बार में निष्पादित करने से पहले कुछ मापदंडों के आधार पर एक स्ट्रिंग में कमांड-लाइन बनाती है। प्रत्येक स्ट्रिंग को डेटा के "स्ट्रीमिंग" को सुविधाजनक बनाने के लिए कमांड स्ट्रिंग को जो भाग समवर्ती होते हैं, उन्हें पाइप द्वारा अलग किया जाना चाहिए।

एक बहुत ही सरल उदाहरण:

#!/bin/bash
part1=gzip -c
part2=some_other_command
cmd="cat infile"

if [ ! "$part1" = "" ]
then
    cmd+=" | $part1"
fi


if [ ! "$part2" = "" ]
then
    cmd+=" | $part2"
fi


cmd+="> outfile"
#show command. It looks ok
echo $cmd
#run the command. fails with pipes
$cmd

किसी कारण से पाइप काम नहीं कर रहे हैं। जब मैं इस स्क्रिप्ट को चलाता हूं तो मुझे कमांड के पहले भाग (पहले पाइप से पहले) से संबंधित विभिन्न त्रुटि संदेश मिलते हैं।

तो मेरा सवाल यह है कि इस तरह से कमांड बनाना संभव है या नहीं, और इसे करने का सबसे अच्छा तरीका क्या है?


त्रुटि संदेश क्या हैं?
कैमरूननमो

मेरी स्क्रिप्ट में (जो इस सरलीकरण से कुछ अधिक जटिल है) मुझे "फाइल नहीं मिली"
लेनर रोलैंड

क्या यह मान लेना सुरक्षित है कि infileवर्तमान निर्देशिका में मौजूद है?
सियारकोट Jun५

हाँ। मेरे कोड में यह wget -O है - एक फ़ाइल के बजाय। वास्तव में, अगर मैं सिर्फ संघटित स्ट्रिंग की नकल करता हूं और टर्मिनल में इसे ठीक करता हूं, तो यह ठीक चलता है
लेनरर्ट रोलैंड

जवाबों:


17

यह सब तब निर्भर करता है जब चीजों का मूल्यांकन किया जाता है। जब आप टाइप करते हैं $cmd, तो बाकी की पूरी पंक्ति पहले शब्द में तर्क के रूप में पारित हो जाती है $cmd

walt@spong:~(0)$ a="cat /etc/passwd"
walt@spong:~(0)$ b="| wc -l"
walt@spong:~(0)$ c="$a $b"
walt@spong:~(0)$ echo $c
cat /etc/passwd | wc -l
walt@spong:~(0)$ $c
cat: invalid option -- 'l'
Try 'cat --help' for more information.
walt@spong:~(1)$ eval $c
62
walt@spong:~(0)$ a="echo /etc/passwd"
walt@spong:~(0)$ c="$a $b"
walt@spong:~(0)$ echo $c
echo /etc/passwd | wc -l
walt@spong:~(0)$ $c
/etc/passwd | wc -l
walt@spong:~(0)$ $c |od -bc
0000000 057 145 164 143 057 160 141 163 163 167 144 040 174 040 167 143  
          /   e   t   c   /   p   a   s   s   w   d       |       w   c  
0000020 040 055 154 012  
              -   l  \n  
0000024
walt@spong:~(0)$ eval $c
1  

इससे पता चलता है कि echoकमांड में दिए गए तर्क हैं: " /etc/passwd", " |" (ऊर्ध्वाधर बार चरित्र), " wc" और " -l"।

से man bash:

eval [arg ...]  
    The  args  are read and concatenated together into   
    a single command.  This command is then read and  
    executed by the shell, and its exit status is returned  
    as the value of eval.  If there are no args, or only null  
    arguments, eval returns 0.

8

इसका एक समाधान, भविष्य के संदर्भ के लिए, "eval" का उपयोग करना है। यह सुनिश्चित करता है कि जिस तरह से बैश द्वारा स्ट्रिंग की व्याख्या की गई है वह भूल गया है और पूरी चीज को पढ़ा जाता है जैसे कि यह सीधे एक शेल में टाइप किया गया था (जो वास्तव में हम चाहते हैं)।

तो ऊपर के उदाहरण में, जगह

$cmd

साथ में

eval $cmd

उसे हल कर लिया।


हालांकि उद्धृत मापदंडों के साथ सावधान रहें। eval foo "a b"जैसा होगा वैसा ही होगा eval foo "a" "b"
udondan

2

@wtinator ने पहले ही समझाया कि यह आपकी अपेक्षा के अनुरूप काम क्यों नहीं करता है। bash -cअपने आदेश को निष्पादित करने के लिए इसका उपयोग करने का एक और तरीका है :

$ comm="cat /etc/passwd"
$ comm+="| wc -l"
$ $comm
cat: invalid option -- 'l'
Try 'cat --help' for more information.
$ bash -c "$comm"
51

1
पारसीमोनी मुझसे कहता है कि किसी अन्य प्रक्रिया को शुरू न करें bash -c, लेकिन evalवर्तमान प्रक्रिया में कमांड का उपयोग करने के लिए।
वॉल्टिनेटर

@waltinator यकीन है, मैं शायद इसके लिए भी eval का उपयोग करूँगा (यही वजह है कि मैंने आपको और Lennart को उभार दिया)। मैं सिर्फ एक विकल्प प्रदान कर रहा हूं।
टेराडॉन

0

संभवतः ऐसा करने का एक बेहतर तरीका यह है कि evalबस बैश सरणी का उपयोग करने से बचें और यह सभी तर्कों का निर्माण करने के लिए इनलाइन विस्तार है और फिर उन्हें कमांड के खिलाफ निष्पादित करें।

runcmd=() # This is slightly messier than declare -a but works
for cmd in $part1 $part2 $part3; do runcmd+="| $cmd "; done
cat infile ${runcmd[@]} # You might be able to do $basecmd ${runcmd[@]}
# but that sometimes requires an `eval` which isn't great
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.