कमांड तर्क के रूप में बैश में सीमांकित पाठ फ़ाइल को पार्स करना


10

मेरे पास एक टेक्स्ट फ़ाइल है, जैसे:

field1,field2,field3 
xield1,xield2,xield3 
dield1,dield2,dield3 
gield1,gield2,gield3

इनमें से प्रत्येक कॉलम एक प्रोग्राम का एक पैरामीटर होगा, और मैं चाहूंगा कि प्रोग्राम को प्रत्येक लाइन के लिए बुलाया जाए

मैं एक पाश के लिए उम्मीद कर रहा था, कुछ इस तरह:

for $i in file
    command $field2 -x $field3 -PN -$field1 >> output
done

बैश में कुछ इस तरह से पूरा करने का सबसे अच्छा तरीका क्या होगा?


खेतों की संख्या स्थिर है?
यूसुफ आर।

@JosephR। हाँ, वे हमेशा 3 हैं
डीन

जवाबों:


7
while IFS=, read xx yy zz;do
    echo $xx $yy $zz
done < input_file

यदि खेतों की संख्या स्थिर है तो यह काम करना चाहिए। इसके बजाय echoअपने आदेश का उपयोग करें।


धन्यवाद, मैं सिर्फ यह कोशिश कर रहा था, लेकिन यह केवल पहली पंक्ति के लिए काम करता है। जैसे ही एक कमांड सफल होता है यह अगले एक की कोशिश नहीं करता है, अगर यह विफल हो जाता है तो यह अगले एक की कोशिश करेगा हालांकि ...
डीन

सफलता से आपका क्या मतलब है या असफल? आपकी आज्ञा क्या करती है?
coffeMug

मुझे लगता है कि वह जो कमांड चला रहा है वह "इनपुट" पढ़ने से पहले मानक इनपुट पढ़ रहा है।
'19

4

आपको बिल्ट-इन के whileसाथ उपयोग करना चाहिए read:

while IFS= read -r line;do
    fields=($(printf "%s" "$line"|cut -d',' --output-delimiter=' ' -f1-))
    command "${fields[1]}" -x "${fields[2]}" ... # ${fields[1]} is field 2
done < your_file_here

यह कैसे काम करता है

  • cutबयान लाइन लेता है और सीमांकक द्वारा निर्दिष्ट पर यह विभाजन -d
  • --output-delimiterविभाजक वर्ण कि है cutतो हम सरणी में विभिन्न क्षेत्रों डाल सकते हैं यहाँ हम एक जगह का चयन, चयनित फ़ील्ड प्रदर्शित करने के लिए प्रयोग करेंगे fields
  • अंत में, हम सभी फ़ील्ड (फ़ील्ड 1 से अंत तक) चाहते हैं और यही वह जगह -f1-है जहाँ खेलना आता है।
  • अब आपके पास सरणी चर में संग्रहीत अलग-अलग फ़ील्ड हैं fields, आप किसी भी विशेष फ़ील्ड को सिंटैक्स के साथ एक्सेस कर सकते हैं, ${field[number]}जहाँ numberआप वास्तविक फ़ील्ड संख्या से कम चाहते हैं, क्योंकि सरणी इंडेक्स बश में शून्य-आधारित है।

ध्यान दें

  • यह विफल हो जाएगा अगर आपके किसी भी क्षेत्र में व्हॉट्सएप हो।

लगातार खेतों की संख्या के लिए

आप इसके बजाय 1_CR के उत्तर के समान कुछ कर सकते हैं :

while IFS= read -r line;do
    IFS=, read -r field1 field2 field3 <<-EOI
    $line
    EOI
    command "$field2" -x "$field3" ... 
done < your_file_here

उपरोक्त, अधिक शोर-शराबा करते हुए, किसी भी POSIX- अनुरूप शेल में काम करना चाहिए, न कि केवल बैश।


यह उस फ़ाइल को नहीं पढ़ रहा है जिससे मुझे परेशानी है, यह कॉलम में लाइन को तोड़ रही है।
डीन

@ डीन हां, सॉरी। मैं ध्यान नहीं दे रहा था। उस पर अब काम हो रहा है।
यूसुफ आर।

@ अद्यतन अद्यतन देखें। मैं जल्द ही एक स्पष्टीकरण जोड़ूंगा।
जोसेफ आर।

@JosephR।, आह्वान IFSमें उचित मूल्य पर सेट करके विभाजन के लिए बाहरी उपकरणों का उपयोग करने से बचना संभव हैread
iruvar

@ 1_CR मुझे पता है, धन्यवाद। मैं बस उस :)
जोसेफ आर।

1

आप readप्रत्येक पंक्ति को उचित रूप ,से सेट करके एक सरणी में विभाजित कर सकते हैं IFS

while IFS=, read -r -a input; do
 printf "%s\n" "${input[0]}" "${input[1]}"
done < input.txt

इसलिए ऊपर दिए गए उदाहरण में, आप प्रत्येक एरे तत्व को इसके इंडेक्स का उपयोग कर सकते हैं, ० से शुरू कर सकते हैं।


1

यह awkवन-लाइनर वही करेगा जो आप चाहते हैं:

awk -F, '{cmd="echo " $2 " -x " $3 " -PN " $1 ">> output";  system(cmd)}' f.txt

echoअपने आदेश के साथ बदलें और f.txtउस फ़ाइल के साथ जिसे आप के माध्यम से पुनरावृत्त करना चाहते हैं।

संक्षिप्त विवरण: परिसीमनकर्ता के रूप में -F,सेट करेगा ,cmdकमांड बनाता है और कमांड को system(cmd)कॉल करता है।


1

ग्नू सेड का भी उपयोग किया जा सकता है।

sed infile -e 's!^\([^,]*\),\([^,]*\),\([^,]*\)$!command \1 -x \2 -PN \3!e' >> output

ई विकल्प के उपयोग को एस कमांड को नोटिस करें

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