जवाबों:
निम्न समाधान एक फ़ाइल से पढ़ता है यदि स्क्रिप्ट को फ़ाइल नाम के साथ पहले पैरामीटर के रूप में कहा जाता है $1
अन्यथा मानक इनपुट से।
while read line
do
echo "$line"
done < "${1:-/dev/stdin}"
प्रतिस्थापन ${1:-...}
को $1
परिभाषित किया जाता है, अन्यथा स्वयं की प्रक्रिया के मानक इनपुट का फ़ाइल नाम उपयोग किया जाता है।
/proc/$$/fd/0
और के बीच कोई अंतर है /dev/stdin
? मैंने देखा कि उत्तरार्द्ध अधिक सामान्य प्रतीत होता है और अधिक सीधा दिखता है।
-r
अपने read
आदेश में जोड़ने के लिए बेहतर है , ताकि यह गलती से \
चरस न खाए ; while IFS= read -r line
व्हाट्सएप को अग्रणी और अनुगामी बनाने के लिए उपयोग करें।
/bin/sh
- क्या आप इसके अलावा bash
या किसी अन्य शेल का उपयोग कर रहे हैं sh
?
शायद सबसे सरल समाधान एक विलय पुनर्निर्देशित ऑपरेटर के साथ स्टड को पुनर्निर्देशित करना है:
#!/bin/bash
less <&0
स्टड फ़ाइल डिस्क्रिप्टर शून्य है। उपरोक्त आपके bash स्क्रिप्ट में पाई गई इनपुट को कम स्टड में भेजता है।
<&0
इस स्थिति में उपयोग करने का कोई लाभ नहीं है - आपका उदाहरण इसके साथ या इसके बिना भी काम करेगा - प्रतीत होता है कि, उपकरण जो आप एक bash स्क्रिप्ट के भीतर से डिफ़ॉल्ट रूप से आह्वान करते हैं, वही स्टड स्वयं स्क्रिप्ट के रूप में देखते हैं (जब तक कि स्क्रिप्ट पहले इसका सेवन नहीं करती)।
यहाँ सबसे आसान तरीका है:
#!/bin/sh
cat -
उपयोग:
$ echo test | sh my_script.sh
test
चर को स्टडिन असाइन करने के लिए , आप उपयोग कर सकते हैं: STDIN=$(cat -)
या बस के STDIN=$(cat)
रूप में ऑपरेटर आवश्यक नहीं है ( @ mklement0 टिप्पणी के अनुसार )।
मानक इनपुट से प्रत्येक पंक्ति को पार्स करने के लिए , निम्न स्क्रिप्ट आज़माएँ:
#!/bin/bash
while IFS= read -r line; do
printf '%s\n' "$line"
done
फ़ाइल या स्टडिन से पढ़ने के लिए (यदि तर्क मौजूद नहीं है), आप इसे इस तक बढ़ा सकते हैं:
#!/bin/bash
file=${1--} # POSIX-compliant; ${1:--} can be used either.
while IFS= read -r line; do
printf '%s\n' "$line" # Or: env POSIXLY_CORRECT=1 echo "$line"
done < <(cat -- "$file")
टिप्पणियाँ:
-
read -r
- किसी विशेष तरीके से बैकस्लैश चरित्र का इलाज न करें। इनपुट लाइन का हिस्सा बनने के लिए प्रत्येक बैकलैश पर विचार करें।- बिना सेटिंग के
IFS
, डिफ़ॉल्ट रूप से Spaceऔर Tabलाइनों की शुरुआत और अंत में (ट्रिम की गई) अनदेखी की जाती है।- खाली लाइनों को प्रिंट करने से बचने
printf
केecho
लिए इसका उपयोग करें जब लाइन में एकल-e
,-n
या हो-E
। हालाँकि इसमें एक वर्कअराउंड हैenv POSIXLY_CORRECT=1 echo "$line"
जिसका उपयोग करके आपके बाहरी GNUecho
को निष्पादित करता है जो इसका समर्थन करता है। देखें: मैं "-ई" कैसे गूंजूं?
देखें: जब कोई तर्क पारित नहीं किया जाता है तो स्टड कैसे पढ़ें? स्टैकओवरफ्लो एसई पर
[ "$1" ] && FILE=$1 || FILE="-"
है FILE=${1:--}
। (वक्रोक्ति: पर्यावरण चर के साथ नाम टकराव से बचने के लिए सभी अपरकेस शेल चर से बचने के लिए बेहतर है ।)
${1:--}
है POSIX अनुरूप, तो यह गोले सभी POSIX की तरह में काम करना चाहिए। ऐसे सभी गोले में जो काम नहीं करेगा वह प्रक्रिया प्रतिस्थापन है ( <(...)
); उदाहरण के लिए, यह bash, ksh, zsh में काम करेगा, लेकिन डैश में नहीं। इसके अलावा, -r
अपने read
आदेश में जोड़ने के लिए बेहतर है , ताकि यह गलती से \
चरस न खाए ; व्हाट्सएप IFS=
को अग्रणी और अनुगामी बनाने के लिए तैयार करना।
echo
: यदि एक पंक्ति में शामिल हैं -e
, -n
या -E
, यह नहीं दिखाया जाएगा। इसे ठीक करने के लिए, आप का उपयोग करना चाहिए printf
: printf '%s\n' "$line"
। मैंने इसे अपने पिछले संपादन में शामिल नहीं किया ... जब मैं इस त्रुटि को ठीक करता हूं तो अक्सर मेरे संपादन रोलबैक हो जाते हैं :(
।
--
बेकार है अगर पहला तर्क है'%s\n'
IFS=
साथ read
और printf
इसके बजाय का उपयोग करेंगे echo
। :)
।
मुझे लगता है कि यह सीधा-सीधा तरीका है:
$ cat reader.sh
#!/bin/bash
while read line; do
echo "reading: ${line}"
done < /dev/stdin
-
$ cat writer.sh
#!/bin/bash
for i in {0..5}; do
echo "line ${i}"
done
-
$ ./writer.sh | ./reader.sh
reading: line 0
reading: line 1
reading: line 2
reading: line 3
reading: line 4
reading: line 5
read
stdin से पढ़ता है डिफ़ॉल्ट रूप से है, तो वहाँ कोई जरूरत के लिए < /dev/stdin
।
echo
समाधान नई लाइनों जब भी कहते हैं IFS
इनपुट धारा टूट जाता है। @ fgm के उत्तर को थोड़ा संशोधित किया जा सकता है:
cat "${1:-/dev/stdin}" > "${2:-/dev/stdout}"
read
के व्यवहार: जबकि read
करता संभावित वर्ण द्वारा कई टोकन में विभाजित। इसमें निहित है $IFS
, यह केवल एक एकल टोकन देता है यदि आप केवल एक एकल चर नाम निर्दिष्ट करते हैं (लेकिन डिफ़ॉल्ट रूप से ट्रिम्स और अग्रणी और अनुगामी व्हाट्सएप)।
read
और $IFS
- झंडे के echo
बिना खुद नई लाइनें जोड़ता हूं -n
। "इको यूटिलिटी किसी भी निर्दिष्ट ऑपरेंड को लिखती है, जो सिंगल ब्लैंक (` ') कैरेक्टर्स द्वारा अलग किया जाता है और उसके बाद एक न्यूलाइन (`\ n') कैरेक्टर को स्टैंडर्ड आउटपुट में लाया जाता है।"
\n
है echo
: पर्ल के पास रीड लाइन की समाप्ति रेखा $_
शामिल है \n
, जबकि बैश read
नहीं है। (हालांकि, @gniourf_gniourf कहीं और इंगित करता है, और अधिक मजबूत दृष्टिकोण के printf '%s\n'
बदले में उपयोग करना है echo
)।
प्रश्न में पर्ल लूप कमांड लाइन पर सभी फ़ाइल नाम तर्कों से या किसी फ़ाइल के निर्दिष्ट न होने पर मानक इनपुट से पढ़ता है । यदि कोई फ़ाइल निर्दिष्ट नहीं है, तो मैं जो उत्तर देखता हूं, वे सभी किसी एकल फ़ाइल या मानक इनपुट को संसाधित करते हैं।
यद्यपि अक्सर यूयूओसी (बेकार उपयोग cat
) के रूप में सटीक रूप से व्युत्पन्न किया जाता है , ऐसे समय होते हैं जब cat
नौकरी के लिए सबसे अच्छा उपकरण होता है, और यह यकीन है कि यह उनमें से एक है:
cat "$@" |
while read -r line
do
echo "$line"
done
इसका एकमात्र नकारात्मक पहलू यह है कि यह एक उप-शेल में चलने वाली पाइपलाइन बनाता है, इसलिए while
लूप में चर असाइनमेंट जैसी चीजें पाइपलाइन के बाहर पहुंच योग्य नहीं हैं। जिस bash
तरह से चारों ओर प्रक्रिया प्रतिस्थापन है :
while read -r line
do
echo "$line"
done < <(cat "$@")
यह while
लूप को मुख्य शेल में छोड़ता है , इसलिए लूप में सेट किए गए वेरिएबल लूप के बाहर पहुंचते हैं।
>>EOF\n$(cat "$@")\nEOF
। अंत में, एक वक्रोक्ति: पर्ल में while IFS= read -r line
क्या while (<>)
होता है, इसका एक बेहतर अनुमान है (व्हाट्सएप को अग्रणी और अनुगामी बना देता है - हालांकि पर्ल भी अनुगामी रहता है \n
)।
ओपी में दिए गए कोड के साथ पर्ल का व्यवहार, कोई भी या कई तर्क नहीं ले सकता है, और यदि कोई तर्क एकल हाइफ़न है, तो -
इसे स्टडिन के रूप में समझा जाता है। इसके अलावा, हमेशा फ़ाइल नाम के साथ संभव है $ARGV
। अब तक दिए गए उत्तरों में से कोई भी वास्तव में इन मामलों में पर्ल के व्यवहार की नकल नहीं करता है। यहाँ एक शुद्ध बैश संभावना है। चाल का exec
उचित उपयोग करना है।
#!/bin/bash
(($#)) || set -- -
while (($#)); do
{ [[ $1 = - ]] || exec < "$1"; } &&
while read -r; do
printf '%s\n' "$REPLY"
done
shift
done
में उपलब्ध है $1
।
यदि कोई तर्क नहीं दिया जाता है, तो हम कृत्रिम -
रूप से पहले स्थितीय पैरामीटर के रूप में सेट होते हैं । हम फिर मापदंडों पर लूप करते हैं। यदि कोई पैरामीटर नहीं है -
, तो हम फ़ाइल नाम से मानक इनपुट को पुनर्निर्देशित करते हैं exec
। यदि यह पुनर्निर्देशन सफल होता है तो हम एक while
लूप के साथ लूप करते हैं। मैं मानक REPLY
चर का उपयोग कर रहा हूं , और इस मामले में आपको रीसेट करने की आवश्यकता नहीं है IFS
। यदि आप कोई दूसरा नाम चाहते हैं, तो आपको ऐसा अवश्य करना चाहिए IFS
(जब तक, निश्चित रूप से, आप ऐसा नहीं चाहते हैं और जानते हैं कि आप क्या कर रहे हैं):
while IFS= read -r line; do
printf '%s\n' "$line"
done
अधिक सटीकता से...
while IFS= read -r line ; do
printf "%s\n" "$line"
done < file
IFS=
और -r
करने के लिए read
आदेश सुनिश्चित करें कि प्रत्येक पंक्ति पढ़ी जाती है असंशोधित (प्रमुख और रिक्त स्थान को अनुगामी सहित)।
कृपया निम्नलिखित कोड आज़माएँ:
while IFS= read -r line; do
echo "$line"
done < file
read
को IFS=
और उसके स्वस्थ उद्धरण के बिना -r
गरीबों $line
को देखकर खड़ा नहीं हो सकता ।
read -r
संकेतन को नापसंद करता हूं । IMO, POSIX को गलत मिला; विकल्प को बैकस्लैश को पीछे हटाने के लिए विशेष अर्थ को सक्षम करना चाहिए, इसे अक्षम नहीं करना चाहिए - ताकि मौजूदा स्क्रिप्ट (POSIX मौजूद होने से पहले) टूट न -r
जाए क्योंकि छोड़ा गया था। मैं, हालांकि, यह IEEE 1003.2 1992 का हिस्सा था, जो कि POSIX खोल और उपयोगिताओं के मानक संस्करण का हिस्सा था, लेकिन यह तब भी एक अतिरिक्त के रूप में चिह्नित किया गया था, इसलिए यह लंबे समय से चले आ रहे अवसरों के बारे में है। मैं कभी परेशानी में नहीं आया क्योंकि मेरा कोड उपयोग नहीं करता है -r
; मैं भाग्यशाली होना चाहिए। इस पर मेरी उपेक्षा करो।
-r
मानक होना चाहिए। मैं मानता हूं कि यह उन मामलों में होने की संभावना नहीं है जहां इसका उपयोग नहीं करने से परेशानी होती है। हालांकि, टूटा हुआ कोड टूटा हुआ कोड है। मेरा संपादन पहली बार उस खराब $line
वैरिएबल से शुरू हुआ था जो अपने उद्धरणों को बुरी तरह से याद करता था। मैंने उस पर read
समय निर्धारित किया । मैंने ठीक नहीं किया echo
क्योंकि यह उस तरह का संपादन है जो वापस लुढ़क जाता है। :(
।
कोड ${1:-/dev/stdin}
केवल पहले तर्क को समझेगा, इसलिए, इस बारे में कैसे।
ARGS='$*'
if [ -z "$*" ]; then
ARGS='-'
fi
eval "cat -- $ARGS" | while read line
do
echo "$line"
done
मुझे इनमें से कोई उत्तर स्वीकार्य नहीं लगता। विशेष रूप से, स्वीकृत उत्तर केवल पहले कमांड लाइन पैरामीटर को संभालता है और बाकी को अनदेखा करता है। पर्ल प्रोग्राम जो यह अनुकरण करने की कोशिश कर रहा है कि सभी कमांड लाइन मापदंडों को संभालता है। तो स्वीकृत जवाब भी सवाल का जवाब नहीं देता है। अन्य उत्तर बैश एक्सटेंशन का उपयोग करते हैं, अनावश्यक 'कैट' कमांड जोड़ते हैं, केवल आउटपुट के लिए इको इनपुट के सरल मामले के लिए काम करते हैं, या बस अनावश्यक रूप से जटिल हैं।
हालाँकि, मुझे उन्हें कुछ श्रेय देना होगा क्योंकि उन्होंने मुझे कुछ विचार दिए। ये रहा पूरा जवाब:
#!/bin/sh
if [ $# = 0 ]
then
DEFAULT_INPUT_FILE=/dev/stdin
else
DEFAULT_INPUT_FILE=
fi
# Iterates over all parameters or /dev/stdin
for FILE in "$@" $DEFAULT_INPUT_FILE
do
while IFS= read -r LINE
do
# Do whatever you want with LINE here.
echo $LINE
done < "$FILE"
done
मैंने उपरोक्त सभी उत्तरों को संयोजित किया और एक शेल फ़ंक्शन बनाया जो मेरी आवश्यकताओं के अनुरूप होगा। यह मेरी 2 विंडोज 10 मशीनों के एक साइबरविन टर्मिनल से है जहां मेरे बीच एक साझा फ़ोल्डर था। मुझे निम्नलिखित को संभालने में सक्षम होना चाहिए:
cat file.cpp | tx
tx < file.cpp
tx file.cpp
जहां एक विशिष्ट फ़ाइल नाम निर्दिष्ट किया गया है, मुझे कॉपी के दौरान उसी फ़ाइलनाम का उपयोग करने की आवश्यकता है। जहां इनपुट डेटा स्ट्रीम को थ्रू पाइप किया गया है, तो मुझे एक अस्थायी फ़ाइल नाम उत्पन्न करना होगा जिसमें घंटे मिनट और सेकंड हों। साझा किए गए मुख्य फ़ोल्डर में सप्ताह के दिनों के सबफ़ोल्डर हैं। यह संगठनात्मक उद्देश्यों के लिए है।
निहारना, मेरी जरूरतों के लिए परम स्क्रिप्ट:
tx ()
{
if [ $# -eq 0 ]; then
local TMP=/tmp/tx.$(date +'%H%M%S')
while IFS= read -r line; do
echo "$line"
done < /dev/stdin > $TMP
cp $TMP //$OTHER/stargate/$(date +'%a')/
rm -f $TMP
else
[ -r $1 ] && cp $1 //$OTHER/stargate/$(date +'%a')/ || echo "cannot read file"
fi
}
अगर कोई ऐसा तरीका है जिसे आप आगे भी इसे अनुकूलित करने के लिए देख सकते हैं, तो मैं जानना चाहूंगा।
निम्नलिखित मानक के साथ काम करता है sh
( dash
डेबियन पर परीक्षण किया गया) और काफी पठनीय है, लेकिन यह स्वाद की बात है:
if [ -n "$1" ]; then
cat "$1"
else
cat
fi | commands_and_transformations
विवरण: यदि पहला पैरामीटर गैर-रिक्त है तो cat
वह फ़ाइल, अन्यथा cat
मानक इनपुट। तब पूरे if
स्टेटमेंट के आउटपुट को प्रोसेस किया जाता है commands_and_transformations
।
cat "${1:--}" | any_command
:। शेल वेरिएबल्स को पढ़ना और उन्हें गूंजना छोटी फाइलों के लिए काम कर सकता है लेकिन इतनी अच्छी तरह से स्केल नहीं करता है।
[ -n "$1" ]
करने के लिए सरल किया जा सकता [ "$1" ]
।
कैसा रहेगा
for line in `cat`; do
something($line);
done
cat
को कमांड लाइन में रखा जाएगा। कमांड लाइन का अधिकतम आकार है। इसके अलावा यह लाइन से लाइन नहीं पढ़ेगा, लेकिन शब्द से शब्द।