প্রতিধ্বনি বনাম <<<, বা বাশ পুরষ্কারে প্রতিধ্বনির অকেজো ব্যবহার?


19

এখন অবধি catপুরষ্কারের অপব্যবহারের ব্যবহারটি খুব সুপরিচিত, এবং একটি অকেজো ব্যবহারেরওecho উল্লেখ রয়েছে (এই প্রশ্নের জন্য প্রাসঙ্গিক নয়)। আমি ভাবছি " echoবাশ পুরষ্কারে অকেজো ব্যবহার" হওয়া উচিত কিনা : পাইপিং কিছু অতি অবৈজ্ঞানিক পরিমাপ অনুসারে বংশগতি ও হিস্ট্রোস্ট্রিংয়ের চেয়ে অনেক ধীর বলে মনে হয়:

  • Heredocs:

    for reps in 1 2 3
    do
        time for i in {1..1000}
        do
            cat <<'END'
    test string
    END
        done > /dev/null
    done
    
    real    0m1.786s
    user    0m0.212s
    sys     0m0.332s
    
    real    0m1.817s
    user    0m0.232s
    sys     0m0.332s
    
    real    0m1.846s
    user    0m0.256s
    sys     0m0.320s
    
  • Herestrings

    for reps in 1 2 3
    do
        time for i in {1..1000}
        do
            cat <<< 'test string'
        done > /dev/null
    done
    
    real    0m1.932s
    user    0m0.280s
    sys     0m0.288s
    
    real    0m1.956s
    user    0m0.248s
    sys     0m0.348s
    
    real    0m1.968s
    user    0m0.268s
    sys     0m0.324s
    
  • ফেরৎ

    for reps in 1 2 3
    do
        time for i in {1..1000}
        do
            echo 'test string' | cat
        done > /dev/null
    done
    
    real    0m3.562s
    user    0m0.416s
    sys     0m0.548s
    
    real    0m3.924s
    user    0m0.384s
    sys     0m0.604s
    
    real    0m3.343s
    user    0m0.400s
    sys     0m0.552s
    

সাধারণভাবে, হেরিডোকস এবং হিস্ট্রোরিংগুলি একই গতি সম্পর্কে (বেশ কয়েকটি পরীক্ষা থেকে এটি কেবল একটি ডেটা সেট করা হয়) যখন পুনঃনির্দেশ ক্রমাগত 50% এর চেয়ে ধীর গতিতে থাকে। আমি কি কিছু ভুল বোঝাবুঝি করছি, বা বাশ-এর ​​স্ট্যান্ডার্ড ইনপুট পড়ার কমান্ডগুলির জন্য এটি সাধারণ নিয়ম হিসাবে ব্যবহার করা যেতে পারে?


4
আমি অবশ্যই আপনাকে "অব্যর্থ ব্যবহারের seq" পুরষ্কারের অনুমতি দেব ;-)
ক্রিস ডাউন

2
নোট করুন যে আপনি স্ট্রিংগুলিতে শেল দ্বারা সমান পরিমাণ বিস্তৃত পরিমাণ তুলনামূলকভাবে cat <<ENDবনাম cat <<< "test string"বনাম echo "test string" | catবা cat <<'END'বনাম cat <<< 'test string'বনাম তুলনা করতে হবে echo 'test string' | cat
manatwork

@ ক্রিসডাউন ডের্প আমি সবসময় এটি ভুলে যাই। ধন্যবাদ!
l0b0

@ মান্যাট ওয়ার্ক ধন্যবাদ, নির্দিষ্ট এবং আপডেট সময়।
l0b0

শুধু একটি কৌতূহল, যে reps সঙ্গে কি? লুপ $ রেপসের সময়টির সাথে আপনার আসল উদ্দেশ্যটি ছিল না $(seq $reps)?
manatwork

উত্তর:


11

প্রথমত, আসুন পারফরম্যান্সে মনোনিবেশ করি। আমি অন্যথায় বেশিরভাগ অলস x86_64 প্রসেসরের সাথে ডেবিয়ান স্কুয়েজ চালানোর জন্য কিছুটা আলাদা প্রোগ্রামের জন্য বেঞ্চমার্ক দৌড়েছি।

herestring.bashইনপুট একটি লাইন পাস করার জন্য একটি স্ট্রিং ব্যবহার করে:

#! /bin/bash
i=0
while [ $i -lt $1 ]; do
  tr a-z A-Z <<<'hello world'
  i=$((i+1))
done >/dev/null

heredoc.bashইনপুট একটি লাইন পাস করার জন্য একটি হেরিডোক ব্যবহার করে:

#! /bin/bash
i=0
while [ $i -lt $1 ]; do
  tr a-z A-Z <<'EOF'
hello world
EOF
  i=$((i+1))
done >/dev/null

echo.bash, echoইনপুট একটি লাইন পাস করতে একটি পাইপ ব্যবহার :

#! /bin/bash
i=0
while [ $i -lt $1 ]; do
  echo 'hello world' | tr a-z A-Z
  i=$((i+1))
done >/dev/null

তুলনা করার জন্য, আমি এটিটি ksh93 এর অধীনে এবং ড্যাশ অধীনে স্ক্রিপ্টগুলিও টাইম করেছিলাম (বাদে herestring.bash, কারণ ড্যাশটিতে ইস্ট্রস্ট্রিংস নেই)।

এখানে তিনবারের মাঝারি রয়েছে:

$ time bash ./herestring.bash 10000
./herestring.bash 10000  0.32s user 0.79s system 15% cpu 7.088 total
$ time ksh ./herestring.bash 10000
ksh ./herestring.bash 10000  0.54s user 0.41s system 17% cpu 5.277 total
$ time bash ./heredoc.bash 10000
./heredoc.bash 10000  0.35s user 0.75s system 17% cpu 6.406 total
$ time ksh ./heredoc.bash 10000  
ksh ./heredoc.sh 10000  0.54s user 0.44s system 19% cpu 4.925 total
$ time sh ./heredoc.bash 10000  
./heredoc.sh 10000  0.08s user 0.58s system 12% cpu 5.313 total
$ time bash ./echo.bash 10000
./echo.bash 10000  0.36s user 1.40s system 20% cpu 8.641 total
$ time ksh ./echo.bash 10000
ksh ./echo.sh 10000  0.47s user 1.51s system 28% cpu 6.918 total
$ time sh ./echo.sh 10000
./echo.sh 10000  0.07s user 1.00s system 16% cpu 6.463 total

উপসংহার:

  • উত্তরাধিকারের চেয়ে উত্তরাধিকারী দ্রুত is
  • echoএবং একটি পাইপ লক্ষণীয়, তবে নাটকীয়ভাবে দ্রুত হয় না। (মনে রাখবেন এটি একটি খেলনা প্রোগ্রাম: একটি বাস্তব প্রোগ্রামে, প্রসেসিংয়ের বেশিরভাগ সময় trকলটি এখানেই আসে in
  • আপনি যদি গতি চান তবে ডাচ বাশ এবং কল ড্যাশ বা তার চেয়ে ভাল ksh করুন। বাশের বৈশিষ্ট্যগুলি আপেক্ষিক স্বচ্ছলতার জন্য তৈরি করে না, তবে ksh বৈশিষ্ট্য এবং গতি উভয়ই রয়েছে।

পারফরম্যান্সের বাইরে, স্পষ্টতা এবং বহনযোগ্যতাও রয়েছে। <<<একটি ksh93 / বাশ / zsh এক্সটেনশন যা কম echo … |বা বেশি পরিচিত <<। এটি ksh88 / pdksh বা POSIX sh এ কাজ করে না।

একমাত্র জায়গা যেখানে <<<তাত্পর্যপূর্ণভাবে উল্লেখযোগ্যভাবে পরিষ্কার হয় একটি বংশের ভিতরে:

foo=$(tr a-z A-Z <<<'hello world')

বনাম

foo=$(tr a-z A-Z <<'EOF'
hello world
EOF
)

(বেশিরভাগ শেলগুলি লাইনের সমাপ্তি শেষে বন্ধনী বন্ধ করার সাথে সামলাতে পারে না <<EOF))


2
নোট যেটি <<<এসেছে rcএবং প্রথমে বোর্নের মতো শেল বিশ্বে আনা হয়েছিল zshrcএকটি পিছনে নতুন লাইন যোগ করা হয়নি, কিন্তু সব bash, zshএবং ksh93AFAICT করুন। rcসেখানে একটি নল ব্যবহার করে, যখন bash, zshএবং ksh93heredocs জন্য মত একটি অস্থায়ী ফাইল ব্যবহার করুন।
স্টাফেন চেজেলাস

@ স্টেফেন চ্যাজেলাস ওফস, আমার চেক করা উচিত ছিল, ধন্যবাদ। এটি <<<আরও কম দরকারী করে তোলে ।
গিলস 'অসন্তুষ্ট হওয়া বন্ধ করুন'

এছাড়াও নোট করুন যে কার্যকরভাবে একটি টেম্প ফাইল তৈরি করতে zshএকটি অপ্টিমাইজেশন =(<<<foo)রয়েছে যার মধ্যে "foo" রয়েছে যা কোনও প্রক্রিয়া যেমন করাকে জড়িত করে না =(echo foo)
স্টাফেন চেজেলাস

আমি আরও উল্লেখ করব যে পিডিএক্স অন্তর্ভুক্ত নয়<<<
কুর্তেম

@kurtm "এটা ksh88 / pdksh অথবা POSIX SH কাজ করে না।"
গিলেজ 'SO- স্টপ হচ্ছে মন্দ'

6

হেরডোকস ব্যবহার করার আরেকটি কারণ (যদি আপনার পর্যাপ্ত পরিমাণ না থাকে) হ'ল প্রবাহটি গ্রাস না করা হলে প্রতিধ্বনি ব্যর্থ হতে পারে। বাশ ' pipefailবিকল্প থাকা বিবেচনা করুন :

set -o pipefail
foo=yawn
echo $foo | /bin/true ; echo $?  # returns 0

/bin/trueএটির স্ট্যান্ডার্ড ইনপুট গ্রাস করে না, তবে echo yawnতা সম্পূর্ণ করে। তবে, যদি প্রতিধ্বনিকে প্রচুর ডেটা মুদ্রণ করতে বলা হয়, তবে এটি শেষ না হওয়া পর্যন্ত শেষ হবে না true:

foo=$(cat /etc/passwd)
# foo now has a fair amount of data

echo $foo | /bin/true ; echo $?  # returns 0 sometimes 141
echo $foo$foo$foo$foo | /bin/true ; echo $?  # returns mostly 141

141 হ'ল সিপাইপ (128 + 13) (128 যোগ করা হচ্ছে কারণ ব্যাশ ব্যাশ (1) অনুসারে এটি করে:

যখন কোনও কমান্ড মারাত্মক সিগন্যাল এন-তে সমাপ্ত হয়, তখন ব্যাশ 128 + এন এর মান প্রস্থান স্থিতি হিসাবে ব্যবহার করে।

বংশগতদের এই সমস্যা নেই:

/bin/true <<< $foo$foo$foo$foo ; echo $?  # returns 0 always

ধন্যবাদ, এই বিশেষ উপবৃত্তিটি আমার স্ক্রিপ্টটি এলোমেলোভাবে এলোমেলোভাবে জায়গায় ব্যর্থ করেছিল, কেভিএম হোস্টের চেয়ে অ্যামাজন সার্ভারগুলিতে, তবে এটি সময়ে সময়ে অসম্ভব - অসম্ভব-অসম্ভব ব্যর্থ জায়গায়। এটি একটি ভাল জিনিস যে pipefailডিফল্ট অফ হওয়া থেকে!
মোগসি

2
ওহ, আমি pipefailপ্রতিটি স্ক্রিপ্টের শীর্ষে সক্ষম করি । গিমে সব ত্রুটি!
l0b0

@ l0b0 হুমম। সম্ভবত আমি j.mp/safebash এ পাইপফেইল যুক্ত করব আমি বিকাশের সময় সমস্ত ত্রুটি পাওয়ার জন্য আছি!
ব্রুনো ব্রোনোস্কি

2

আপনি ইকোটি ব্যবহার করতে চাইতে পারেন তার একটি কারণ হেরিডোকস এবং হেরোস্ট্রিংসের শেষে যুক্ত হওয়া নিউলাইন চরিত্রটিকে কিছুটা নিয়ন্ত্রণে রাখতে হবে:

তিনটি অক্ষরের fooদৈর্ঘ্য 3:

$ echo -n foo | wc -c
3

তবে, এখানে একটি থ্রিচার্যাক্টর চারটি অক্ষর:

$ wc -c <<< foo
4

একটি তিন-চরিত্রের হেরডোকও:

$ wc -c << EOF
foo
EOF
4

চতুর্থ চরিত্রটি একটি নতুন লাইনের 0x0aচরিত্র।

উপ-শেল থেকে আউটপুট ধরার সময় বাশ যেভাবে এই নতুন লাইনের অক্ষরগুলি সরিয়ে দেয় তাতে কোনওভাবেই এই ম্যাজিকালি ফিট করে:

এখানে একটি কমান্ড যা চারটি অক্ষর প্রদান করে: fooএবং \n। ইকো দ্বারা '\ n' যুক্ত করা হয়, আপনি -nবিকল্পটি নির্দিষ্ট না করে এটি সর্বদা একটি নতুন লাইন অক্ষর যুক্ত করে :

$ echo foo
foo
$ echo foo | wc -c
4

যাইহোক, এটিকে একটি ভেরিয়েবলের দ্বারা নির্ধারিত করে, প্রতিধ্বনির সাহায্যে যুক্ত করা নতুন লাইন সরানো হবে:

$ foo=$(echo foo)
$ echo "$foo" # here, echo adds a newline too.
foo

সুতরাং আপনি যদি ফাইল এবং ভেরিয়েবলগুলি মিশ্রণ করেন এবং সেগুলি গণনায় ব্যবহার করেন (যেমন, আপনি হেরিডোক বা হিস্ট্রোরিং ব্যবহার করতে পারবেন না, কারণ তারা একটি নতুন লাইন যুক্ত করবে।

foo=abc
echo -n 'abc' > something.txt
if [ $(wc -c <<< "$foo") -eq $(wc -c < something.txt) ] ; then
  echo "yeah, they're the same!"
else
  echo "foo and bar have different lengths (except, maybe not)"
fi

আপনি যদি বিবৃতিটি পড়তে পরিবর্তন করেন

if [ $(echo -n "$foo" | wc -c) -eq $(wc -c < something.txt) ] ; then

তারপর পরীক্ষা পাস।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.