मैं एक कमांड के तर्कों के रूप में फ़ाइल की लाइनों का उपयोग कैसे करूं?


159

कहते हैं, मेरे पास तर्क foo.txtनिर्दिष्ट करने वाली एक फाइल Nहै

arg1
arg2
...
argN

जिसे मुझे कमांड पास करने की आवश्यकता है my_command

मैं एक कमांड के तर्कों के रूप में फ़ाइल की लाइनों का उपयोग कैसे करूं?


10
"तर्क", बहुवचन, या "तर्क", एकल? स्वीकृत उत्तर केवल एकल-तर्क मामले में सही है - जो कि शरीर पाठ के बारे में पूछताछ करता है - लेकिन बहु-तर्क मामले में नहीं, जिस पर विषय पूछताछ के लिए प्रकट होता है।
चार्ल्स डफी

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

जवाबों:


237

यदि आपका शेल (दूसरों के बीच) बैश $(cat afile)है $(< afile), तो इसके लिए एक शॉर्टकट है , इसलिए आप लिखेंगे:

mycommand "$(< file.txt)"

'कमांड सब्स्टीट्यूशन' सेक्शन में बैश मैन पेज में प्रलेखित।

पूरी तरह से, आपका आदेश स्टड से पढ़ा गया है, इसलिए: mycommand < file.txt


11
पांडित्यपूर्ण होने के लिए, <ऑपरेटर का उपयोग करने के लिए यह शॉर्टकट नहीं है । इसका मतलब है कि शेल स्वयं catपुनर्निर्देशन गुण के बजाय बाइनरी को निष्पादित करने के बजाय पुनर्निर्देशन करेगा ।
lstyls

2
यह कर्नेल सेटिंग है, इसलिए आपको कर्नेल को फिर से कनेक्ट करना होगा। या xargs कमांड की जांच करें
ग्लेन जैकमैन

3
@ykaner क्योंकि के बिना "$(…)", की सामग्री file.txtमानक इनपुट के लिए पारित किया जाएगा mycommand, एक तर्क के रूप में नहीं। "$(…)"इसका मतलब है कि कमांड चलाएं और आउटपुट को एक स्ट्रिंग के रूप में वापस दें ; यहाँ "कमांड" केवल फ़ाइल को पढ़ता है लेकिन यह अधिक जटिल हो सकता है।
13

3
यह मेरे लिए काम नहीं कर रहा है जब तक कि मैं उद्धरण नहीं खोता। उद्धरण के साथ, यह पूरी फाइल को 1 तर्क के रूप में लेता है। उद्धरण के बिना, यह प्रत्येक पंक्ति को एक अलग arg के रूप में व्याख्या करता है।
पीट

1
@ लार्श तुम बिल्कुल सही हो। यह एक कम भ्रमित करने का तरीका है, धन्यवाद।
23

37

जैसा कि पहले ही उल्लेख किया गया है, आप बैकटिक्स का उपयोग कर सकते हैं या $(cat filename)

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

a "b c" d

आपको जो तर्क मिलेंगे वो हैं:

a
"b
c"
d

यदि आप एक तर्क के रूप में प्रत्येक पंक्ति को खींचना चाहते हैं, तो समय का उपयोग करें / पढ़ें / निर्माण करें:

while read i ; do command_name $i ; done < filename

मुझे उल्लेख करना चाहिए था, मैं मान रहा हूं कि आप बैश का उपयोग कर रहे हैं। मुझे लगता है कि वहाँ अन्य गोले हैं, लेकिन लगभग सभी * निक्स मशीनें जो मैंने काम की हैं, वे या तो भाग गई हैं या कुछ बराबर हैं। IIRC, इस सिंटैक्स को ksh और zsh पर समान काम करना चाहिए।
विल

1
read -rजब तक आप बैकस्लैश-एस्केप सीक्वेंस का विस्तार नहीं करना चाहते हैं, तब तक पढ़ें और न्यूलाइन की तुलना में एनयूएल एक सुरक्षित परिसीमन है, खासकर यदि आप जो तर्क दे रहे हैं वह फाइलनाम जैसी चीजें हैं, जिसमें शाब्दिक न्यूलाइन्स शामिल हो सकते हैं। इसके अलावा, IFS को साफ किए बिना, आपको व्हाट्सएप का प्रमुख और अनुगामी बना दिया जाता है i
चार्ल्स डफी

18
command `< file`

स्टड पर कमांड को फाइल कंटेंट पास करेंगे, लेकिन नए सिरे से स्ट्रिप करेंगे, जिसका अर्थ है कि आप प्रत्येक लाइन पर व्यक्तिगत रूप से पुनरावृति नहीं कर सकते। उसके लिए आप 'लूप' के लिए एक स्क्रिप्ट लिख सकते हैं:

for line in `cat input_file`; do some_command "$line"; done

या (बहु-पंक्ति संस्करण):

for line in `cat input_file`
do
    some_command "$line"
done

या ( $()इसके बजाय बहु-लाइन संस्करण ``):

for line in $(cat input_file)
do
    some_command "$line"
done

संदर्भ:

  1. लूप सिंटैक्स के लिए: https://www.cyberciti.biz/faq/bash-for-loop/

इसके अलावा, < fileबैकटिक्स में डालने का मतलब है कि यह वास्तव commandमें बिल्कुल भी पुनर्निर्देशन नहीं करता है ।
चार्ल्स डफी

3
(क्या जिन लोगों ने इसे अपवित्र किया था, वे वास्तव में इसका परीक्षण command `< file` करते हैं ; या तो बैश या पोसिक्स श में काम नहीं करता है , ज़ीश एक अलग मामला है, लेकिन यह शेल इस प्रश्न के बारे में नहीं है)।
चार्ल्स डफी

@CharlesDuffy क्या आप इस बारे में अधिक विशिष्ट हो सकते हैं कि यह कैसे काम नहीं करता है?
mwfearnley

@CharlesDuffy यह bash 3.2 और zsh 5.3 में काम करता है। यह श, एश और डैश में काम नहीं करेगा, लेकिन न तो $ (<फ़ाइल)।
अरनी 97

1
@mwearnley, कि विशिष्टता प्रदान करने के लिए खुश। लक्ष्य लाइनों पर पुनरावृति करना है, है ना? Hello Worldएक लाइन पर रखो । आप इसे पहली बार देखेंगे some_command Hello, फिर some_command World, या नहींsome_command "Hello World"some_command Hello World
चार्ल्स डफी

15

आप ऐसा करते हैं कि backticks का उपयोग करते हुए:

echo World > file.txt
echo Hello `cat file.txt`

4
यह एक तर्क नहीं बनाता है - क्योंकि यह उद्धृत नहीं किया गया है, यह स्ट्रिंग-विभाजन के अधीन है, इसलिए यदि आप echo "Hello * Starry * World" > file.txtपहले चरण में उत्सर्जित होते हैं, तो आपको कम से कम चार अलग-अलग तर्क प्राप्त होंगे जो दूसरी कमांड को दिए गए हैं - और संभावना अधिक, के रूप में *रों फ़ाइलों के नाम का विस्तार होगा मौजूदा निर्देशिका में प्रस्तुत करते हैं।
चार्ल्स डफी

3
... और क्योंकि यह ग्लोब विस्तार चल रहा है, यह वास्तव में फ़ाइल में क्या है उत्सर्जन नहीं करता हैऔर क्योंकि यह एक कमांड प्रतिस्थापन ऑपरेशन का प्रदर्शन कर रहा है, यह बेहद अक्षम है - यह वास्तव में fork()एक उप-समूह के साथ एक उपप्रकार को अपने स्टडआउट से जुड़ा हुआ है, फिर /bin/catउस उप-समूह के बच्चे के रूप में आह्वान करता है, फिर FIFO के माध्यम से आउटपुट पढ़ता है; से तुलना करें $(<file.txt), जो फ़ाइल की सामग्री को सीधे उपखंड या एफआईएफओ के साथ बैश में पढ़ता है।
चार्ल्स डफी

11

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


एक फ़ाइल लिखने के लिए, तर्कों की एक सरणी दी गई है:

printf '%s\0' "${arguments[@]}" >file

... आदि के साथ "argument one", "argument two"उपयुक्त के रूप में बदलें ।


उस फ़ाइल से पढ़ने के लिए और उसकी सामग्री (bash, ksh93, या सरणियों के साथ एक और हालिया शेल) का उपयोग करने के लिए:

declare -a args=()
while IFS='' read -r -d '' item; do
  args+=( "$item" )
done <file
run_your_command "${args[@]}"

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

set --
while IFS='' read -r -d '' item; do
  set -- "$@" "$item"
done <file
run_your_command "$@"

ध्यान दें कि -d(एक अलग एंड-ऑफ़-लाइन सीमांकक का उपयोग करने की अनुमति देना) एक गैर-पॉसिक्स एक्सटेंशन है, और एरे के बिना एक शेल भी इसका समर्थन नहीं कर सकता है। ऐसा होना चाहिए, आपको NUL- सीमांकित सामग्री को एक eval-safe में बदलने के लिए एक गैर-शेल भाषा का उपयोग करने की आवश्यकता हो सकती है :

quoted_list() {
  ## Works with either Python 2.x or 3.x
  python -c '
import sys, pipes, shlex
quote = pipes.quote if hasattr(pipes, "quote") else shlex.quote
print(" ".join([quote(s) for s in sys.stdin.read().split("\0")][:-1]))
  '
}

eval "set -- $(quoted_list <file)"
run_your_command "$@"

6

यहां बताया गया है कि मैं कमांड के तर्क के रूप में फ़ाइल की सामग्री कैसे पास करता हूं:

./foo --bar "$(cat ./bar.txt)"

1
यह है - लेकिन पर्याप्त रूप से कम कुशल होने के लिए - प्रभावी रूप से समतुल्य है $(<bar.txt)(एक शेल का उपयोग करते समय, जैसे बैश, उचित विस्तार के साथ)। $(<foo)एक विशेष मामला है: नियमित रूप से कमांड प्रतिस्थापन के विपरीत, जैसा कि प्रयोग किया जाता है $(cat ...), यह एक उपखंड को चालू करने के लिए बंद नहीं करता है, और इस तरह ओवरहेड के एक महान सौदे से बचा जाता है।
चार्ल्स डफी

3

यदि आपको केवल इतना करना है कि arguments.txtसामग्री के साथ फाइल को चालू करना है

arg1
arg2
argN

में my_command arg1 arg2 argNतो आप बस का उपयोग कर सकते xargs:

xargs -a arguments.txt my_command

आप xargsकॉल में अतिरिक्त स्थिर तर्क रख सकते हैं , जैसे xargs -a arguments.txt my_command staticArgकॉल करेंगेmy_command staticArg arg1 arg2 argN


1

मेरे बैश शेल में निम्नलिखित एक आकर्षण की तरह काम करता है:

cat input_file | xargs -I % sh -c 'command1 %; command2 %; command3 %;'

जहां input_file है

arg1
arg2
arg3

जैसा कि स्पष्ट है, यह आपको इनपुट_फाइल से प्रत्येक पंक्ति के साथ कई कमांड निष्पादित करने की अनुमति देता है, एक अच्छी छोटी चाल जिसे मैंने यहां सीखा ।


3
आपकी "अच्छी छोटी चाल" सुरक्षा के दृष्टिकोण से खतरनाक है - यदि आपके पास कोई तर्क है $(somecommand), तो आपको उस आदेश को पाठ के रूप में पारित करने के बजाय निष्पादित किया जाएगा। इसी तरह, >/etc/passwdपुनर्निर्देशन और अधिलेखित /etc/passwd(यदि उपयुक्त अनुमति के साथ चलाया जाए), आदि के रूप में संसाधित किया जाएगा
चार्ल्स डफी

2
इसके बजाय निम्न करना अधिक सुरक्षित है (जीएनयू एक्सटेंशन वाले सिस्टम पर): xargs -d $'\n' sh -c 'for arg; do command1 "$arg"; command2 "arg"; command3 "arg"; done' _- और भी अधिक कुशल, क्योंकि यह आपके इनपुट फ़ाइल में प्रति पंक्ति एक शेल शुरू करने के बजाय प्रत्येक शेल के लिए उतने ही तर्क देता है।
चार्ल्स डफी

और हां, cat
ट्रिपल

0

संपादन के बाद @Wesley चावल का जवाब दो बार, मैंने तय कर लिया अपने परिवर्तनों को सिर्फ उसके जवाब को बदलने के बजाय अपने खुद के लेखन जारी रखने के लिए बहुत बड़ा मिल रहे थे। इसलिए, मैंने फैसला किया कि मुझे अपना खुद का लिखना होगा!

किसी फ़ाइल की प्रत्येक पंक्ति को इस तरह पढ़ें और इस तरह से लाइन-बाय-लाइन पर काम करें:

#!/bin/bash
input="/path/to/txt/file"
while IFS= read -r line
do
  echo "$line"
done < "$input"

यह लेखक विवेक गीते के यहाँ से सीधे आता है: https://www.cyberciti.biz/faq/unix-howto-read-line-by-line-from-file/ । उसे श्रेय जाता है!

सिंटैक्स: एक बैश यूनिक्स और लिनक्स शेल पर लाइन द्वारा फ़ाइल लाइन पढ़ें:
1. वाक्य रचना इस प्रकार है कि बैश, ksh, zsh, और अन्य सभी शेल के लिए लाइन
2 से फ़ाइल लाइन पढ़ने के लिए निम्न है । while read -r line; do COMMAND; done < input.file
3. -rविकल्प कमांड पढ़ने के लिए पारित बैकस्लैश की व्याख्या करने से बचता है।
4. IFS=व्हाट्सएप को प्रमुख / अनुगामी व्हाट्सएप को ट्रिम करने से रोकने के लिए पढ़ने से पहले विकल्प जोड़ें -
5।while IFS= read -r line; do COMMAND_on $line; done < input.file


और अब इस बंद प्रश्न का उत्तर देने के लिए जो मेरे पास भी था: क्या यह संभव है `एक फ़ाइल से फ़ाइलों की सूची` को जोड़ने के लिए? - यहाँ मेरा जवाब है:

ध्यान दें कि FILES_STAGEDएक चर एक फाइल के लिए पूर्ण पथ से युक्त है जिसमें लाइनों का एक गुच्छा होता है जहां प्रत्येक पंक्ति एक फ़ाइल के लिए एक रिश्तेदार पथ है जिसे मैं करना चाहता हूं git add। यह कोड स्निपेट इस परियोजना में "eRCaGuy_dotfiles / useful_scripts / Sync_git_repo_to_build_machine.sh" फ़ाइल का हिस्सा बनने वाला है , ताकि एक पीसी से विकास में फ़ाइलों के आसान समन्वय को सक्षम किया जा सके (उदा: एक कंप्यूटर I कोड ऑन) से दूसरे (पूर्व: एक)। अधिक शक्तिशाली कंप्यूटर जो मैं बना रहा हूं): https://github.com/ElectricRCAircraftGuy/eRCaGuy_dotfiles

while IFS= read -r line
do
    echo "  git add \"$line\""
    git add "$line" 
done < "$FILES_STAGED"

संदर्भ:

  1. मैंने अपना उत्तर कहां से कॉपी किया: https://www.cyberciti.biz/faq/unix-howto-read-line-by-line-from-file/
  2. लूप सिंटैक्स के लिए: https://www.cyberciti.biz/faq/bash-for-loop/

सम्बंधित:

  1. फ़ाइल लाइन-बाय-लाइन की सामग्री को कैसे पढ़ें और उस git addपर काम करें: क्या किसी फ़ाइल से फ़ाइलों की सूची को `git add` करना संभव है?
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.