कमांड के तर्क के रूप में टेक्स्ट फ़ाइल की प्रत्येक पंक्ति को कैसे पास करें?


42

मैं एक स्क्रिप्ट लिखने के लिए देख रहा हूं जो .txtएक तर्क के रूप में एक फ़ाइल नाम लेता है , लाइन द्वारा फाइल लाइन पढ़ता है, और प्रत्येक पंक्ति को एक कमांड में पास करता है। उदाहरण के लिए, यह चलता है command --option "LINE 1", command --option "LINE 2"आदि, कमांड का आउटपुट दूसरी फाइल पर लिखा जाता है। मैं इसे कैसे करूं? मुझे नहीं पता कि कहां से शुरू किया जाए।

जवाबों:


26

while readलूप का उपयोग करें :

: > another_file  ## Truncate file.

while IFS= read -r LINE; do
    command --option "$LINE" >> another_file
done < file

एक और ब्लॉक द्वारा आउटपुट को रीडायरेक्ट करना है:

while IFS= read -r LINE; do
    command --option "$LINE"
done < file > another_file

अंतिम फ़ाइल खोलने के लिए है:

exec 4> another_file

while IFS= read -r LINE; do
    command --option "$LINE" >&4
    echo xyz  ## Another optional command that sends output to stdout.
done < file

यदि कोई कमांड इनपुट पढ़ता है, तो इनपुट के लिए दूसरे fd का उपयोग करना एक अच्छा विचार होगा, इसलिए कमांड इसे नहीं खाएंगे (यहां मान लें ksh, zshया इसके bashलिए -u 3, <&3इसके बजाय उपयोग करें )

while IFS= read -ru 3 LINE; do
    ...
done 3< file

अंत में तर्क स्वीकार करने के लिए, आप कर सकते हैं:

#!/bin/bash

FILE=$1
ANOTHER_FILE=$2

exec 4> "$ANOTHER_FILE"

while IFS= read -ru 3 LINE; do
    command --option "$LINE" >&4
done 3< "$FILE"

जो एक के रूप में चला सकता है:

bash script.sh file another_file

अतिरिक्त विचार। bashउपयोग के साथ readarray:

readarray -t LINES < "$FILE"

for LINE in "${LINES[@]}"; do
    ...
done

ध्यान दें: IFS=यदि आपको लाइन मानों को अग्रणी और अनुगामी स्थानों की छंटनी करने का मन नहीं है तो छोड़ा जा सकता है।


28

एक अन्य विकल्प है xargs

GNU के साथ xargs:

< file xargs -I{} -d'\n' command --option {} other args

{} पाठ की पंक्ति के लिए स्थान धारक है।

अन्य के xargsपास नहीं है -d, लेकिन कुछ के पास -0एनयूएल-सीमांकित इनपुट के लिए है। उन लोगों के साथ, आप यह कर सकते हैं:

< file tr '\n' '\0' | xargs -0 -I{} command --option {} other args

यूनिक्स-अनुरूप सिस्टम पर ( -IPOSIX में वैकल्पिक है और केवल यूनिक्स-अनुरूप सिस्टम के लिए आवश्यक है), आपको अपेक्षित प्रारूप में लाइनों को उद्धृत करने के लिए इनपुट को प्रीप्रोसेस करना होगा xargs:

< file sed 's/"/"\\""/g;s/.*/"&"/' |
  xargs -E '' -I{} command --option {} other args

हालाँकि, ध्यान दें कि कुछ xargsकार्यान्वयन में तर्क के अधिकतम आकार (उदाहरण के लिए सोलारिस पर 255, यूनिक्स विनिर्देश द्वारा अनुमत न्यूनतम) पर बहुत कम सीमा है।


reducible to<file xargs -L 1 -I{} command --option {} other args
iruvar

@iruvar, नहीं, वह उद्धरण संसाधित करेगा और कुछ रिक्तियां निकाल देगा।
स्टीफन चेजालस

7

सवाल को ठीक रखते हुए:

#!/bin/bash

# xargs -n param sets how many lines from the input to send to the command

# Call command once per line
[[ -f $1 ]] && cat $1 | xargs -n1 command --option

# Call command with 2 lines as args, such as an openvpn password file
# [[ -f $1 ]] && cat $1 | xargs -n2 command --option

# Call command with all lines as args
# [[ -f $1 ]] && cat $1 | xargs command --option

1
आकर्षण की तरह काम किया :-)
BugHunter

3

मुझे मिला सबसे अच्छा जवाब है:

for i in `cat`; do "$cmd" "$i"; done < $file

संपादित करें:

... चार साल बाद ...

कई डाउन वोट और कुछ और अनुभव के बाद मैं अब निम्नलिखित की सिफारिश करूंगा

xargs -l COMMAND < file

3
यह फ़ाइल में प्रत्येक शब्द के लिए एक बार कमांड को आमंत्रित करेगा । इसके अलावा, आपको हमेशा शेल वेरिएबल्स (जैसे do "$cmd" "$i";) में संदर्भों को उद्धृत करना चाहिए जब तक कि आपके पास कोई कारण न हो; यदि फ़ाइल में *स्वयं द्वारा एक शब्द के रूप में सम्‍मिलित है, तो आपका कोड रन करेगा $cmd *, जो निश्चित रूप से वर्तमान निर्देशिका में फ़ाइलों की सूची के साथ कमांड चलाएगा।
जी-मैन का कहना है 'मोनिका'

1
@ जी-मैन, को छोड़कर zsh, `cat`पहले से ही विस्तार करेगा *(निर्विवाद $iअभी भी कुछ वाइल्डकार्ड (एक दूसरे दौर) का विस्तार कर सकता है यदि कुछ का विस्तार `cat`)। किसी भी मामले में, यह दृष्टिकोण वास्तव में गलत है।
स्टीफन चेजलस

1
+1। यह ठीक काम करेगा, अगर प्रत्येक पंक्ति में केवल रिक्त स्थान के बिना कमांड के लिए आवश्यक इनपुट शामिल है।
सबिन सेबस्टियन

यह प्रत्येक शब्द पर कार्य करता है, क्या इसका एक प्रकार है जो प्रत्येक पंक्ति पर कार्य करता है?
thebunnyrules

सवाल लाइन द्वारा फाइलनाम लाइन की एक सूची को संसाधित करने का था।
स्टीफन रोलर

2
    sed "s/'/'\\\\''/g;s/.*/\$* '&'/" <<\FILE |\
    sh -s -- command echo --option
all of the{&}se li$n\es 'are safely shell
quoted and handed to command as its last argument
following --option, and, here, before that echo
FILE

आउटपुट

--option all of the{&}se li$n\es 'are safely shell
--option quoted and handed to command as its last argument
--option following --option, and, here, before that echo

-2
ed file.txt
%g/^/s// /
2,$g/^/-,.j
1s/^/command/
wq
chmod 755 file.txt
./file.txt

किसी फ़ाइल की सभी पंक्तियों को लें और उन्हें एक ही आदेश के तर्क के रूप में पास करें,

command line1 line2 line3 ....

यदि आपको --optionप्रत्येक पंक्ति को दूसरी पंक्ति बदलने से पहले ध्वज की आवश्यकता है:

%g/^/s// --option /

1
एड का उपयोग करने के लिए क्या -1 ... वास्तव में?
user2217522

3
मैंने आपको निराश नहीं किया, लेकिन जिस व्यक्ति के पास शायद ये कारण थे: (1) यह वह नहीं करता है जो सवाल पूछता है। यह कमांड लाइन पर फ़ाइल की सभी सामग्री के साथ एक बार कमांड को आमंत्रित करता है; बल्कि प्रति पंक्ति एक बार । (2) यह उन अक्षरों को संभालने के लिए कुछ नहीं करता है जो शेल के लिए विशेष हैं (जो फ़ाइल में हो सकता है); जैसे, ', ", <, >, ;, आदि (3) यह एक अनावश्यक अस्थायी फ़ाइल बनाता है। (४) इस तरह की चीजें आम तौर पर "यहां दस्तावेजों" के साथ की जाती हैं। (५) आपकी edआज्ञा अनाड़ी है; पहले दो आदेशों को कम किया जा सकता है %s/^/ /और %j
जी-मैन का कहना है कि 'मोनिका'
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.