कहते हैं, मेरे पास तर्क foo.txt
निर्दिष्ट करने वाली एक फाइल N
है
arg1
arg2
...
argN
जिसे मुझे कमांड पास करने की आवश्यकता है my_command
मैं एक कमांड के तर्कों के रूप में फ़ाइल की लाइनों का उपयोग कैसे करूं?
कहते हैं, मेरे पास तर्क foo.txt
निर्दिष्ट करने वाली एक फाइल N
है
arg1
arg2
...
argN
जिसे मुझे कमांड पास करने की आवश्यकता है my_command
मैं एक कमांड के तर्कों के रूप में फ़ाइल की लाइनों का उपयोग कैसे करूं?
जवाबों:
यदि आपका शेल (दूसरों के बीच) बैश $(cat afile)
है $(< afile)
, तो इसके लिए एक शॉर्टकट है , इसलिए आप लिखेंगे:
mycommand "$(< file.txt)"
'कमांड सब्स्टीट्यूशन' सेक्शन में बैश मैन पेज में प्रलेखित।
पूरी तरह से, आपका आदेश स्टड से पढ़ा गया है, इसलिए: mycommand < file.txt
<
ऑपरेटर का उपयोग करने के लिए यह शॉर्टकट नहीं है । इसका मतलब है कि शेल स्वयं cat
पुनर्निर्देशन गुण के बजाय बाइनरी को निष्पादित करने के बजाय पुनर्निर्देशन करेगा ।
"$(…)"
, की सामग्री file.txt
मानक इनपुट के लिए पारित किया जाएगा mycommand
, एक तर्क के रूप में नहीं। "$(…)"
इसका मतलब है कि कमांड चलाएं और आउटपुट को एक स्ट्रिंग के रूप में वापस दें ; यहाँ "कमांड" केवल फ़ाइल को पढ़ता है लेकिन यह अधिक जटिल हो सकता है।
जैसा कि पहले ही उल्लेख किया गया है, आप बैकटिक्स का उपयोग कर सकते हैं या $(cat filename)
।
जो उल्लेख नहीं किया गया था, और मुझे लगता है कि नोट करना महत्वपूर्ण है, यह है कि आपको यह याद रखना चाहिए कि शेल उस फ़ाइल की सामग्री को व्हाट्सएप के अनुसार तोड़ देगा, प्रत्येक "शब्द" को यह एक तर्क के रूप में आपकी कमांड को देता है। और जब आप उद्धरणों में एक कमांड-लाइन तर्क को संलग्न करने में सक्षम हो सकते हैं ताकि इसमें व्हाट्सएप, एस्केप सीक्वेंस आदि शामिल हो सकें, तो फ़ाइल से पढ़ना एक ही काम नहीं करेगा। उदाहरण के लिए, यदि आपकी फ़ाइल में निम्न शामिल हैं:
a "b c" d
आपको जो तर्क मिलेंगे वो हैं:
a
"b
c"
d
यदि आप एक तर्क के रूप में प्रत्येक पंक्ति को खींचना चाहते हैं, तो समय का उपयोग करें / पढ़ें / निर्माण करें:
while read i ; do command_name $i ; done < filename
read -r
जब तक आप बैकस्लैश-एस्केप सीक्वेंस का विस्तार नहीं करना चाहते हैं, तब तक पढ़ें और न्यूलाइन की तुलना में एनयूएल एक सुरक्षित परिसीमन है, खासकर यदि आप जो तर्क दे रहे हैं वह फाइलनाम जैसी चीजें हैं, जिसमें शाब्दिक न्यूलाइन्स शामिल हो सकते हैं। इसके अलावा, IFS को साफ किए बिना, आपको व्हाट्सएप का प्रमुख और अनुगामी बना दिया जाता है i
।
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
< file
बैकटिक्स में डालने का मतलब है कि यह वास्तव command
में बिल्कुल भी पुनर्निर्देशन नहीं करता है ।
command `< file`
करते हैं ; या तो बैश या पोसिक्स श में काम नहीं करता है , ज़ीश एक अलग मामला है, लेकिन यह शेल इस प्रश्न के बारे में नहीं है)।
Hello World
एक लाइन पर रखो । आप इसे पहली बार देखेंगे some_command Hello
, फिर some_command World
, या नहीं । some_command "Hello World"
some_command Hello World
आप ऐसा करते हैं कि backticks का उपयोग करते हुए:
echo World > file.txt
echo Hello `cat file.txt`
echo "Hello * Starry * World" > file.txt
पहले चरण में उत्सर्जित होते हैं, तो आपको कम से कम चार अलग-अलग तर्क प्राप्त होंगे जो दूसरी कमांड को दिए गए हैं - और संभावना अधिक, के रूप में *
रों फ़ाइलों के नाम का विस्तार होगा मौजूदा निर्देशिका में प्रस्तुत करते हैं।
fork()
एक उप-समूह के साथ एक उपप्रकार को अपने स्टडआउट से जुड़ा हुआ है, फिर /bin/cat
उस उप-समूह के बच्चे के रूप में आह्वान करता है, फिर FIFO के माध्यम से आउटपुट पढ़ता है; से तुलना करें $(<file.txt)
, जो फ़ाइल की सामग्री को सीधे उपखंड या एफआईएफओ के साथ बैश में पढ़ता है।
यदि आप इसे एक मजबूत तरीके से करना चाहते हैं जो हर संभव कमांड लाइन तर्क के लिए काम करता है (रिक्त स्थान के साथ मान, 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 "$@"
यहां बताया गया है कि मैं कमांड के तर्क के रूप में फ़ाइल की सामग्री कैसे पास करता हूं:
./foo --bar "$(cat ./bar.txt)"
$(<bar.txt)
(एक शेल का उपयोग करते समय, जैसे बैश, उचित विस्तार के साथ)। $(<foo)
एक विशेष मामला है: नियमित रूप से कमांड प्रतिस्थापन के विपरीत, जैसा कि प्रयोग किया जाता है $(cat ...)
, यह एक उपखंड को चालू करने के लिए बंद नहीं करता है, और इस तरह ओवरहेड के एक महान सौदे से बचा जाता है।
यदि आपको केवल इतना करना है कि 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
मेरे बैश शेल में निम्नलिखित एक आकर्षण की तरह काम करता है:
cat input_file | xargs -I % sh -c 'command1 %; command2 %; command3 %;'
जहां input_file है
arg1
arg2
arg3
जैसा कि स्पष्ट है, यह आपको इनपुट_फाइल से प्रत्येक पंक्ति के साथ कई कमांड निष्पादित करने की अनुमति देता है, एक अच्छी छोटी चाल जिसे मैंने यहां सीखा ।
$(somecommand)
, तो आपको उस आदेश को पाठ के रूप में पारित करने के बजाय निष्पादित किया जाएगा। इसी तरह, >/etc/passwd
पुनर्निर्देशन और अधिलेखित /etc/passwd
(यदि उपयुक्त अनुमति के साथ चलाया जाए), आदि के रूप में संसाधित किया जाएगा
xargs -d $'\n' sh -c 'for arg; do command1 "$arg"; command2 "arg"; command3 "arg"; done' _
- और भी अधिक कुशल, क्योंकि यह आपके इनपुट फ़ाइल में प्रति पंक्ति एक शेल शुरू करने के बजाय प्रत्येक शेल के लिए उतने ही तर्क देता है।
संपादन के बाद @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"
git add
पर काम करें: क्या किसी फ़ाइल से फ़ाइलों की सूची को `git add` करना संभव है?