নিম্নলিখিত পার্ল স্ক্রিপ্ট ( my.pl
) কমান্ড লাইন আরগের ফাইল বা STDIN থেকে পড়তে পারে:
while (<>) {
print($_);
}
perl my.pl
stdin থেকে পড়তে হবে, যখন perl my.pl a.txt
থেকে পড়তে হবে a.txt
। এটি খুব সুবিধাজনক।
ভাবছেন বাশের সমতুল্য কি আছে?
নিম্নলিখিত পার্ল স্ক্রিপ্ট ( my.pl
) কমান্ড লাইন আরগের ফাইল বা STDIN থেকে পড়তে পারে:
while (<>) {
print($_);
}
perl my.pl
stdin থেকে পড়তে হবে, যখন perl my.pl a.txt
থেকে পড়তে হবে a.txt
। এটি খুব সুবিধাজনক।
ভাবছেন বাশের সমতুল্য কি আছে?
উত্তর:
স্ক্রিপ্টটিকে প্রথম পরামিতি হিসাবে কোনও ফাইলের নাম দিয়ে $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
স্টিডিন ফাইল বর্ণনাকারী শূন্য। উপরেরগুলি আপনার ব্যাশ স্ক্রিপ্টে পাইপযুক্ত ইনপুটটি কম স্টিডিনে প্রেরণ করে।
<&0
এই পরিস্থিতিতে ব্যবহার করার কোনও সুবিধা নেই - আপনার উদাহরণটি এর সাথে বা এটি ছাড়া একইভাবে কাজ করবে - আপাতদৃষ্টিতে, আপনি যে সরঞ্জামগুলি ডিফল্টরূপে বাশ স্ক্রিপ্টের মধ্য থেকে আহ্বান করেছেন সেগুলি স্ক্রিপ্টের মতো একই স্টিডিন দেখতে পাবে (স্ক্রিপ্টটি প্রথমে ব্যবহার না করে)।
এখানে সহজ উপায়:
#!/bin/sh
cat -
ব্যবহার:
$ echo test | sh my_script.sh
test
বরাদ্দ করতে stdin পরিবর্তনশীল জন্য, আপনাকে ব্যবহার করতে পারেন: 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
পরিবর্তে ব্যবহার করুন । তবে এটি ব্যবহার করে আপনার বাইরের জিএনইউ কার্যকর করে যা এটি সমর্থন করে এমন এক কার্যকারিতা রয়েছে । দেখুন: আমি কীভাবে "-e" প্রতিধ্বনি করব?echo
-e
-n
-E
env POSIXLY_CORRECT=1 echo "$line"
echo
দেখুন: কোন যুক্তি পাস না হলে স্টিডিন কীভাবে পড়বেন? স্ট্যাকওভারফ্লো এসই তে
[ "$1" ] && FILE=$1 || FILE="-"
করতে পারে FILE=${1:--}
। (কুইবল: এনভায়রনমেন্ট ভেরিয়েবলের সাথে নামের সংঘর্ষ এড়াতে অল-স্কয়ার শেল ভেরিয়েবলগুলি এড়ানো ভাল ))
${1:--}
হয় POSIX-অনুবর্তী, তাই এটি শাঁস সব POSIX মত কাজ করা উচিত নয়। এই ধরনের সমস্ত শেলগুলিতে যা কাজ করবে না তা হ'ল প্রক্রিয়া প্রতিস্থাপন ( <(...)
); এটি ব্যাশ, কেএসএস, জেডএসে কাজ করবে তবে উদাহরণস্বরূপ ড্যাশ নয়। এছাড়াও, -r
আপনার read
আদেশে যুক্ত করা আরও ভাল , যাতে এটি ঘটনাক্রমে \
চরগুলি না খায় ; পূর্বে লিখুন IFS=
সামনের এবং হোয়াইটস্পেস trailing সংরক্ষণে।
echo
: যদি কোনও লাইন থাকে তবে -e
, -n
বা -E
এটি প্রদর্শিত হবে না। এই সমস্যার সমাধান করতে, আপনি ব্যবহার করা আবশ্যক printf
: printf '%s\n' "$line"
। আমি আমার আগের সম্পাদন করা এটা অন্তর্ভুক্ত করা হয়নি ... খুব প্রায়ই আমার সম্পাদনাগুলো rollbacked হয় যখন আমি এই ত্রুটি সংশোধন :(
।
--
প্রথম যুক্তি যদি হয় তবে তা অকেজো'%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') অক্ষর দ্বারা আলাদা করে লিখবে opera"
\n
echo
$_
\n
read
printf '%s\n'
echo
প্রশ্নের পার্ল লুপটি কমান্ড লাইনের সমস্ত ফাইলের নাম আর্গুমেন্ট থেকে বা কোনও ফাইল নির্দিষ্ট না করা থাকলে স্ট্যান্ডার্ড ইনপুট থেকে পড়ে reads আমি যে উত্তরগুলি দেখছি সেগুলিতে কোনও ফাইল নির্দিষ্ট না থাকলে একক ফাইল বা স্ট্যান্ডার্ড ইনপুট প্রক্রিয়াজাত করে।
যদিও প্রায়শই ইউयूওসি ( অব্যর্থ ব্যবহারের 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
কমান্ড নিশ্চিত করে যে প্রতিটি লাইনে পড়া হয় অপরিবর্তিত (সামনের এবং হোয়াইটস্পেস trailing সহ)।
নিম্নলিখিত কোড চেষ্টা করুন:
while IFS= read -r line; do
echo "$line"
done < file
read
ছাড়া IFS=
এবং -r
দরিদ্রদের $line
সুস্থ উদ্ধৃতি না দিয়ে দাঁড়াতে পারিনি ।
read -r
। আইএমও, পসিক্স ভুল পেয়েছে; বিকল্পটিকে ব্যাকস্ল্যাশগুলি অনুসরণ করার জন্য বিশেষ অর্থটি সক্ষম করা উচিত, এটি অক্ষম করা উচিত নয় - যাতে বিদ্যমান স্ক্রিপ্টগুলি (পসিক্সের অস্তিত্বের আগে থেকেই) ভঙ্গ না হয় কারণ -r
বাদ দেওয়া হয়েছিল it তবে আমি পর্যবেক্ষণ করছি যে এটি আইইইই 1003.2 1992 এর অংশ ছিল, যা পসিক্স শেল এবং ইউটিলিটিস স্ট্যান্ডার্ডের প্রথম সংস্করণ ছিল, তবে এটি তখনও একটি সংযোজন হিসাবে চিহ্নিত হয়েছিল, সুতরাং এটি দীর্ঘকালীন সুযোগগুলি সম্পর্কে বিচক্ষণ। আমি কখনই সমস্যায় পড়িনি কারণ আমার কোড ব্যবহার করে না -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
কমান্ড লাইনে স্থাপন করা হবে। কমান্ড লাইনের সর্বাধিক আকার রয়েছে। এছাড়াও এটি লাইন বাই লাইন পড়বে না, তবে শব্দ দিয়ে শব্দ।