linux - बैश में एक फ़ाइल की सामग्री के माध्यम से लूपिंग




bash loops (8)

@ पीटर: यह आपके लिए काम कर सकता है-

echo "Start!";for p in $(cat ./pep); do
echo $p
done

यह आउटपुट वापस कर देगा-

Start!
RKEKNVQ
IPKKLLQK
QYFHQLEKMNVK
IPKKLLQK
GDLSTALEVAIDCYEK
QYFHQLEKMNVKIPENIYR
RKEKNVQ
VLAKHGKLQDAIN
ILGFMK
LEDVALQILL

मैं Bash साथ एक टेक्स्ट फ़ाइल की प्रत्येक पंक्ति के माध्यम से कैसे Bash करूं?

इस स्क्रिप्ट के साथ:

echo "Start!"
for p in (peptides.txt)
do
    echo "${p}"
done

मुझे स्क्रीन पर यह आउटपुट मिलता है:

Start!
./runPep.sh: line 3: syntax error near unexpected token `('
./runPep.sh: line 3: `for p in (peptides.txt)'

(बाद में मैं स्क्रीन पर आउटपुट की तुलना में $ पी के साथ कुछ और जटिल बनाना चाहता हूं।)

पर्यावरण परिवर्तनीय SHELL है (एनवी से):

SHELL=/bin/bash

/bin/bash --version आउटपुट:

GNU bash, version 3.1.17(1)-release (x86_64-suse-linux-gnu)
Copyright (C) 2005 Free Software Foundation, Inc.

cat /proc/version आउटपुट:

Linux version 2.6.18.2-34-default ([email protected]) (gcc version 4.1.2 20061115 (prerelease) (SUSE Linux)) #1 SMP Mon Nov 27 11:46:27 UTC 2006

फ़ाइल peptides.txt में शामिल हैं:

RKEKNVQ
IPKKLLQK
QYFHQLEKMNVK
IPKKLLQK
GDLSTALEVAIDCYEK
QYFHQLEKMNVKIPENIYR
RKEKNVQ
VLAKHGKLQDAIN
ILGFMK
LEDVALQILL

ऐसा करने का एक तरीका यह है:

while read p; do
  echo $p
done <peptides.txt

असाधारण रूप से, यदि लूप बॉडी मानक इनपुट से पढ़ सकता है , तो आप एक अलग फ़ाइल डिस्क्रिप्टर का उपयोग कर फ़ाइल खोल सकते हैं:

while read -u 10 p; do
  ...
done 10<peptides.txt

यहां, 10 सिर्फ एक मनमाना संख्या है (0, 1, 2 से अलग)।


थोड़ी देर लूप का प्रयोग करें, इस तरह:

while IFS= read -r line; do
   echo "$line"
done <file

टिप्पणियाँ:

  1. यदि आप IFS सही तरीके से सेट नहीं करते हैं, तो आप इंडेंटेशन खो देंगे।

  2. आपको लगभग हमेशा पढ़ने के साथ -r विकल्प का उपयोग करना चाहिए।

  3. के साथ लाइनों को मत पढ़ो


मान लें कि आपके पास यह फ़ाइल है:

$ cat /tmp/test.txt
Line 1
    Line 2 has leading space
Line 3 followed by blank line

Line 5 (follows a blank line) and has trailing space    
Line 6 has no ending CR

चार तत्व हैं जो कई बैश समाधानों द्वारा पढ़े गए फ़ाइल आउटपुट के अर्थ को बदल देंगे:

  1. खाली रेखा 4;
  2. दो लाइनों पर अग्रणी या पिछली जगहें;
  3. व्यक्तिगत लाइनों के अर्थ को बनाए रखना (यानी, प्रत्येक पंक्ति एक रिकॉर्ड है);
  4. लाइन 6 को सीआर से समाप्त नहीं किया गया है।

यदि आप रिक्त रेखाओं और सीआर के बिना लाइनों को समाप्त करने सहित लाइन द्वारा टेक्स्ट फ़ाइल लाइन चाहते हैं, तो आपको थोड़ी देर के लूप का उपयोग करना होगा और आपके पास अंतिम पंक्ति के लिए वैकल्पिक परीक्षण होना चाहिए।

यहां वे विधियां हैं जो फ़ाइल को बदल सकती हैं ( cat वापसी के मुकाबले):

1) आखिरी पंक्ति और अग्रणी और पिछली जगहों को खो दें:

$ while read -r p; do printf "%s\n" "'$p'"; done </tmp/test.txt
'Line 1'
'Line 2 has leading space'
'Line 3 followed by blank line'
''
'Line 5 (follows a blank line) and has trailing space'

(यदि आप while IFS= read -rp; do printf "%s\n" "'$p'"; done </tmp/test.txt इसके बजाय while IFS= read -rp; do printf "%s\n" "'$p'"; done </tmp/test.txt किया गया है, आप अग्रणी और पिछली जगहों को संरक्षित करते हैं लेकिन फिर भी अंतिम पंक्ति खो देते हैं इसे सीआर के साथ समाप्त नहीं किया गया है)

2) cat साथ प्रक्रिया प्रतिस्थापन का उपयोग पूरी फाइल को एक गिल्प में पढ़ता है और व्यक्तिगत लाइनों का अर्थ खो देता है:

$ for p in "$(cat /tmp/test.txt)"; do printf "%s\n" "'$p'"; done
'Line 1
    Line 2 has leading space
Line 3 followed by blank line

Line 5 (follows a blank line) and has trailing space    
Line 6 has no ending CR'

(यदि आप " $(cat /tmp/test.txt) से " हटाते हैं तो आप फ़ाइल शब्द को एक $(cat /tmp/test.txt) बजाए शब्द से पढ़ते हैं। शायद यह नहीं कि क्या उद्देश्य है ...)

फ़ाइल लाइन-दर-रेखा को पढ़ने और सभी रिक्तियों को संरक्षित करने का सबसे मजबूत और सरल तरीका यह है:

$ while IFS= read -r line || [[ -n $line ]]; do printf "'%s'\n" "$line"; done </tmp/test.txt
'Line 1'
'    Line 2 has leading space'
'Line 3 followed by blank line'
''
'Line 5 (follows a blank line) and has trailing space    '
'Line 6 has no ending CR'

यदि आप अग्रणी और व्यापारिक जगहों को पट्टी करना चाहते हैं, तो IFS= part को हटाएं:

$ while read -r line || [[ -n $line ]]; do printf "'%s'\n" "$line"; done </tmp/test.txt
'Line 1'
'Line 2 has leading space'
'Line 3 followed by blank line'
''
'Line 5 (follows a blank line) and has trailing space'
'Line 6 has no ending CR'

(समाप्त होने के बिना एक पाठ फ़ाइल \n , काफी आम होने पर, POSIX के तहत टूटा माना जाता है। यदि आप पीछे की ओर गिन सकते हैं \n आपको लूप में || [[ -n $line ]] आवश्यकता नहीं है।)

बाश अकसर किये गए सवाल पर अधिक


यह अन्य उत्तरों की तुलना में बेहतर नहीं है, लेकिन रिक्त स्थान के बिना फ़ाइल में काम करने का एक और तरीका है (टिप्पणियां देखें)। मुझे लगता है कि अलग-अलग स्क्रिप्ट फ़ाइलों का उपयोग करने के अतिरिक्त चरण के बिना मुझे टेक्स्ट फ़ाइलों में सूचियों के माध्यम से खोदने के लिए अक्सर एक-लाइनर की आवश्यकता होती है।

for word in $(cat peptides.txt); do echo $word; done

यह प्रारूप मुझे इसे एक कमांड लाइन में रखने की अनुमति देता है। जो कुछ भी आप चाहते हैं उसे "echo $ word" भाग बदलें और आप अर्धविराम से अलग एकाधिक आदेश जारी कर सकते हैं। निम्न उदाहरण फ़ाइल की सामग्री का उपयोग आपके द्वारा लिखी गई दो अन्य स्क्रिप्ट में तर्क के रूप में करता है।

for word in $(cat peptides.txt); do cmd_a.sh $word; cmd_b.py $word; done

या यदि आप इसका उपयोग स्ट्रीम संपादक (sed सीखना) की तरह करना चाहते हैं तो आप आउटपुट को दूसरी फ़ाइल में डंप कर सकते हैं।

for word in $(cat peptides.txt); do cmd_a.sh $word; cmd_b.py $word; done > outfile.txt

मैंने इन्हें उपरोक्त लिखित रूप में उपयोग किया है क्योंकि मैंने टेक्स्ट फाइलों का उपयोग किया है जहां मैंने उन्हें प्रति पंक्ति एक शब्द के साथ बनाया है। (टिप्पणियां देखें) यदि आपके पास रिक्त स्थान हैं जो आप अपने शब्दों / रेखाओं को विभाजित नहीं करना चाहते हैं, तो यह थोड़ा उलझन में आता है, लेकिन वही आदेश अभी भी निम्नानुसार काम करता है:

OLDIFS=$IFS; IFS=$'\n'; for line in $(cat peptides.txt); do cmd_a.sh $line; cmd_b.py $line; done > outfile.txt; IFS=$OLDIFS

यह सिर्फ शैल को केवल नई लाइनों पर विभाजित करने के लिए बताता है, न कि रिक्त स्थान, फिर पर्यावरण को वापस जो पहले था, वापस लौटाता है। इस बिंदु पर, आप इसे सभी को एक पंक्ति में निचोड़ने के बजाय इसे एक शेल स्क्रिप्ट में डालने पर विचार करना चाहेंगे।

शुभकामनाएँ!


यहां मेरा वास्तविक जीवन उदाहरण है कि किसी अन्य प्रोग्राम आउटपुट की लूप लाइनों को कैसे करें, सबस्ट्रिंग्स की जांच करें, चर से डबल कोट्स ड्रॉप करें, लूप के बाहर उस चर का उपयोग करें। मुझे लगता है कि बहुत से लोग इन प्रश्नों को जल्दी या बाद में पूछ रहे हैं।

##Parse FPS from first video stream, drop quotes from fps variable
## streams.stream.0.codec_type="video"
## streams.stream.0.r_frame_rate="24000/1001"
## streams.stream.0.avg_frame_rate="24000/1001"
FPS=unknown
while read -r line; do
  if [[ $FPS == "unknown" ]] && [[ $line == *".codec_type=\"video\""* ]]; then
    echo ParseFPS $line
    FPS=parse
  fi
  if [[ $FPS == "parse" ]] && [[ $line == *".r_frame_rate="* ]]; then
    echo ParseFPS $line
    FPS=${line##*=}
    FPS="${FPS%\"}"
    FPS="${FPS#\"}"
  fi
done <<< "$(ffprobe -v quiet -print_format flat -show_format -show_streams -i "$input")"
if [ "$FPS" == "unknown" ] || [ "$FPS" == "parse" ]; then 
  echo ParseFPS Unknown frame rate
fi
echo Found $FPS

लूप के बाहर परिवर्तनीय घोषित करें, सेट मान और लूप के बाहर इसका उपयोग करने की आवश्यकता है <<< "$ (...)" वाक्यविन्यास। वर्तमान कंसोल के संदर्भ में आवेदन चलाने की जरूरत है। कमांड के चारों ओर उद्धरण आउटपुट स्ट्रीम की न्यूलाइन रखता है।

सबस्ट्रिंग्स के लिए लूप मैच फिर नाम = मूल्य जोड़ी पढ़ता है, अंतिम = चरित्र के दाहिने तरफ भाग को विभाजित करता है, पहले उद्धरण को छोड़ देता है, अंतिम उद्धरण छोड़ देता है, हमारे पास कहीं और इस्तेमाल करने के लिए एक साफ मूल्य होता है।


#!/bin/bash
#
# Change the file name from "test" to desired input file 
# (The comments in bash are prefixed with #'s)
for x in $(cat test.txt)
do
    echo $x
done

cat peptides.txt | while read line
do
   # do something with $line here
done




io