2011-05-25 15 views
5

यह सवाल 3 भागों में है, और प्रत्येक अकेले आसान है, लेकिन एक साथ संयुक्त नहीं तुच्छ (कम से कम मेरे लिए) है :)शैल स्क्रिप्ट तर्कों में "-" कैसे संभाल लें?

एक स्क्रिप्ट क्या अपने तर्कों के रूप में लेना चाहिए लिखने की आवश्यकता है:

  1. एक आदेश के लिए
  2. कई तर्क एक और आदेश के नाम फ़ाइलों की
  3. सूची

उदाहरण:

./my_script head -100 a.txt b.txt ./xxx/*.txt 
./my_script sed -n 's/xxx/aaa/' *.txt 

और इसी तरह।

किसी कारण मैं भेद

  • आदेश
  • आदेश के लिए तर्क हैं क्या है क्या जरूरत के लिए मेरी स्क्रिप्ट के अंदर
  • क्या फ़ाइलों

तो शायद सबसे रहे हैं मानक तरीका ऊपर दिए गए उदाहरण लिखते हैं:

./my_script head -100 -- a.txt b.txt ./xxx/*.txt 
./my_script sed -n 's/xxx/aaa/' -- *.txt 

प्रश्न 1: क्या कोई बेहतर समाधान है? ./my_script (पहला प्रयास) में

प्रसंस्करण:

command="$1";shift 
args=`echo $* | sed 's/--.*//'` 
filenames=`echo $* | sed 's/.*--//'` 

#... some additional processing ... 

"$command" "$args" $filenames #execute the command with args and files 

यह समाधान विफल हो जाएगा जब filenamesspaces में शामिल होंगे और/या '-', उदा
/कुछ - path/to/अधिक/मूर्खतापूर्ण फ़ाइल name.txt

Question2: कैसे ठीक से $command अपने $args और $filenames बाद में निष्पादन के लिए मिल सकता है?

प्रश्न 3: - निष्पादन की निम्न शैली को कैसे प्राप्त करें?

echo $filenames | $command $args #but want one filename = one line (like ls -1) 

क्या यहां अच्छा खोल समाधान है, या उदाहरण के लिए उपयोग करने की आवश्यकता है?

+1

यह ठीक से जवाब देने के लिए कुछ समय लग जाएगा। 1. बैक-टिक्स का उपयोग क्यों करें?वे रास्ते से वंचित हैं और जब तक आप सोलारिस या एईक्स पर रूट के रूप में बहुत अधिक काम करने की उम्मीद नहीं करते हैं, जरूरी नहीं है। $ (Cmd) का प्रयोग करें! 2. (आपके प्रश्न के लिए अधिक), गेटोपेट और गेटोपेट्स (खोल के लिए) पर पढ़ें। मैंने यहां कई उदाहरण देखे हैं, कम से कम एक जो काफी विस्तृत है। कुछ समय के साथ युग्मित (($ #> 0)) प्रक्रिया करें ARR; खिसक जाना ; किया 'मदद करेगा। 3. केस स्टेटमेंट का उपयोग करने पर विचार करें। '--' के लिए आपको उन्हें बचाना होगा या उन्हें उद्धृत करना होगा या इसे '[-] [-] जैसे charclass में परिवर्तित करना होगा। – shellter

उत्तर

6

सबसे पहले, ऐसा लगता है कि आप एक ऐसी स्क्रिप्ट लिखने की कोशिश कर रहे हैं जो कमांड और फ़ाइल नामों की एक सूची लेता है और बदले में प्रत्येक फ़ाइल नाम पर कमांड चलाता है। इस पार्टी में एक पंक्ति में किया जा सकता है:

 
$ for file in a.txt b.txt ./xxx/*.txt;do head -100 "$file";done 
$ for file in *.txt; do sed -n 's/xxx/aaa/' "$file";done 

हालांकि, शायद मैं गलत व्याख्या की है कि आपकी मंशा तो मेरे अपने प्रश्नों को व्यक्तिगत रूप से उत्तर दे। "-"

इसके बजाय का उपयोग करने का

(जो पहले से ही एक अलग अर्थ है), निम्न सिंटैक्स मेरे लिए और अधिक प्राकृतिक महसूस करता है:

 
./my_script -c "head -100" a.txt b.txt ./xxx/*.txt 
./my_script -c "sed -n 's/xxx/aaa/'" *.txt 

बैश में तर्क को निकालने के लिए, का उपयोग getopts:

SCRIPT=$0 

while getopts "c:" opt; do 
    case $opt in 
     c) 
      command=$OPTARG 
      ;; 
    esac 
done 

shift $((OPTIND-1)) 

if [ -z "$command" ] || [ -z "$*" ]; then 
    echo "Usage: $SCRIPT -c <command> file [file..]" 
    exit 
fi 

आप शेष तर्क से प्रत्येक के लिए एक कमांड को चलाने के लिए चाहते हैं, यह इस तरह दिखेगा:

for target in "[email protected]";do 
    eval $command \"$target\" 
done 

आप STDIN से फाइलनेम्स में पढ़ना चाहते हैं, यह इस तरह के और अधिक दिखेगा:

while read target; do 
    eval $command \"$target\" 
done 
+0

@ टॉमशॉ: अच्छा पहला पोस्ट। कोड के अंतिम ब्लॉक के लिए, शायद आप 'eval' के साथ लूप के इंटीरियर को उपसर्ग करना चाहते हैं। भारी लिस्टिंग करने के लिए धन्यवाद। ;-) – shellter

+0

@shellter: प्रतिक्रिया के लिए धन्यवाद! –

+0

@ jm666: इस अद्यतन संस्करण को अब रिक्त स्थान को संभालना चाहिए। –

0

प्रश्न 1

मैं ऐसा नहीं सोचता, कम से कम नहीं तो आप मनमाने ढंग से आदेश के लिए यह करने के लिए की जरूरत है।

प्रश्न 3

command=$1 
shift 
while [ $1 != '--' ]; do 
    args="$args $1" 
    shift 
done 
shift 
while [ -n "$1" ]; do 
    echo "$1" 
    shift 
done | $command $args 

प्रश्न 2

कैसे है कि 3 सवाल से भिन्न होता है?

+0

$ filenames echo | sed - टूट जाएगा, अगर फ़ाइल नाम रिक्त स्थान है। जैसे echo "file1.txt" "spaces.txt के साथ file2" - इसलिए पूछना - मेरा पहला प्रयास गलत है। – jm666

+0

आह मैं देखता हूं, मेरा जवाब संपादित किया –

3

[email protected] चर, जब उद्धृत समूह मापदंडों में सक्षम हो जाएगा के रूप में वे किया जाना चाहिए:

for parameter in "[email protected]" 
do 
    echo "The parameter is '$parameter'" 
done 

अगर दिया:

head -100 test this "File name" out 

प्रिंट होगा

the parameter is 'head' 
the parameter is '-100' 
the parameter is 'test' 
the parameter is 'this' 
the parameter is 'File name' 
the parameter is 'out' 

अब, आपको बस लूप को पार्स करना है। आप कुछ बहुत ही सरल नियमों का उपयोग कर सकते हैं:

  1. पहले पैरामीटर हमेशा फ़ाइल नाम
  2. पैरामीटर है कि एक पानी का छींटा के साथ शुरू का पालन कर रहे हैं मानकों
  3. के बाद है "-" या एक बार एक नहीं करता ' टी "-" से शुरू नहीं होता, बाकी सभी फाइल नाम हैं।

यदि पैरामीटर में पहले वर्ण इस का उपयोग करते हुए एक पानी का छींटा है देखने के लिए जाँच कर सकते हैं:

if [[ "x${parameter}" == "x${parameter#-}" ]] 

आप इस वाक्य रचना से पहले नहीं देखा है, तो यह एक बाईं फिल्टर है। # परिवर्तनीय नाम के दो भागों को विभाजित करता है। पहला भाग चर का नाम है, और दूसरा ग्लोब फ़िल्टर (नियमित अभिव्यक्ति नहीं) काटने के लिए है। इस मामले में, यह एक ही डैश है। जब तक यह कथन सत्य नहीं है, आप जानते हैं कि आपके पास पैरामीटर है। बीटीडब्ल्यू, x इस मामले में आवश्यक हो सकता है या नहीं भी हो सकता है। जब आप कोई परीक्षण चलाते हैं, और आपके पास एक डैश के साथ एक स्ट्रिंग है, तो परीक्षण परीक्षण के पैरामीटर के लिए गलती कर सकता है, न कि मूल्य।

यह एक साथ रखें कुछ इस तरह होगा:

parameterFlag="" 
for parameter in "[email protected]"  #Quotes are important! 
do 
    if [[ "x${parameter}" == "x${parameter#-}" ]] 
    then 
     parameterFlag="Tripped!" 
    fi 
    if [[ "x${parameter}" == "x--" ]] 
    then 
     print "Parameter \"$parameter\" ends the parameter list" 
     parameterFlag="TRIPPED!" 
    fi 
    if [ -n $parameterFlag ] 
    then 
     print "\"$parameter\" is a file" 
    else 
     echo "The parameter \"$parameter\" is a parameter" 
    fi 
done 
+0

को शामिल किया है 'x' हैक केवल प्राचीन गोले के लिए आवश्यक है। कृपया इसका इस्तेमाल न करें, यह कोड बदसूरत बनाता है। – nyuszika7h

+0

@ nyuszika7h, ... अच्छी तरह से - वहाँ कुछ कोने के मामले जहां आधुनिक शैलियों में भी इसकी आवश्यकता हो सकती है, लेकिन उन मामलों में केवल '[]' ('' [[]] ') में मौजूद नहीं है और जब 'test' तीन से अधिक तर्क पारित किए जाते हैं (इस प्रकार, जब '-a' या '-o' का उपयोग किया जाता है) ... यह कि इसका हिस्सा है कि क्यों POSIX का नवीनतम संस्करण उन्हें बहिष्कृत करता है। –

संबंधित मुद्दे