আমার চলকটি কেন স্থানীয়ভাবে 'পড়ার সময়' লুপে, তবে অন্য একটি আপাতদৃষ্টিতে অনুরূপ লুপে নয়?


25

$xনীচের স্নিপেটগুলি থেকে কেন আমি আলাদা মান পেতে পারি ?

#!/bin/bash

x=1
echo fred > junk ; while read var ; do x=55 ; done < junk
echo x=$x 
#    x=55 .. I'd expect this result

x=1
cat junk | while read var ; do x=55 ; done
echo x=$x 
#    x=1 .. but why?

x=1
echo fred | while read var ; do x=55 ; done
echo x=$x 
#    x=1  .. but why?

উত্তর:


26

ডান ব্যাখ্যা ইতিমধ্যে দেয়া হয়েছে jsbillings এবং geekosaur , কিন্তু আমার একটু যে প্রসারিত করা যাক।

বাশ সহ বেশিরভাগ শেলগুলিতে, পাইপলাইনের প্রতিটি পাশ একটি সাবশেলে চলে, সুতরাং শেলের অভ্যন্তরীণ অবস্থার কোনও পরিবর্তন (যেমন ভেরিয়েবলগুলি নির্ধারণ করা) পাইপলাইনের সেই অংশে সীমাবদ্ধ থাকে। সাব-শেল থেকে আপনি কেবলমাত্র যে তথ্যটি পেতে পারেন তা হ'ল এটি আউটপুট (স্ট্যান্ডার্ড আউটপুট এবং অন্যান্য ফাইল বর্ণনাকারীদের কাছে) এবং এর প্রস্থান কোড (যা 0 এবং 255 এর মধ্যে একটি সংখ্যা)। উদাহরণস্বরূপ, নিম্নলিখিত স্নিপেট 0:

a=0; a=1 | a=2; echo $a

কেএসএসে (এটিএন্ডটি কোড থেকে প্রাপ্ত ভেরিয়েন্টস, পিডিক্স / এমএক্সএইচ রূপগুলি নয়) এবং জেডএস-এ, পাইপলাইনের শেষ আইটেমটি প্যারেন্ট শেলের মধ্যে কার্যকর করা হয়। (POSIX উভয় আচরণের অনুমতি দেয়)) সুতরাং উপরের স্নিপেটটি 2 টি প্রিন্ট করে।

পাইপলাইনে কিছুক্ষণের লুপের ধারাবাহিকতা (বা পাইপলাইনের ডানদিকে আপনার যা কিছু আছে তবে কিছুক্ষণ লুপ আসলে এখানে প্রচলিত রয়েছে) অন্তর্ভুক্ত করা একটি দরকারী প্রতিভা:

cat junk | {
  while read var ; do x=55 ; done
  echo x=$x 
}

1
থ্যাঙ্কস গিলস .. ওটা = 0; a = 1 | a = 2 একটি খুব স্পষ্ট চিত্র দেয় .. এবং কেবলমাত্র অভ্যন্তরীণ অবস্থার স্থানীয়করণের কথা নয়, তবে পাইপলাইনের দ্বারা পাইপের মাধ্যমে আসলে কিছু প্রেরণের দরকার হয় না (প্রস্থান কোড (?) ব্যতীত) নিজেই পাইপের মধ্যে একটি আকর্ষণীয় অন্তর্দৃষ্টি ... আমি আমার স্ক্রিপ্টটি চালিয়ে নেওয়ার ব্যবস্থা করলাম < <(locate -ber ^\.tag$), আসল সামান্য অস্পষ্ট উত্তর এবং গিকোসর এবং গ্লেন জ্যাকম্যানের কমেন্টের জন্য ধন্যবাদ .. উত্তরটি গ্রহণ করার বিষয়ে আমি প্রথমদিকে দ্বিধায় পড়েছিলাম, তবে নেট ফলাফল বেশ পরিষ্কার ছিল, বিশেষত jsbillings ফলো-আপ মন্তব্য সহ :)
পিটার.ও

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

8

আপনি একটি পরিবর্তনশীল স্কোপ ইস্যুতে চলছে running পাইপের ডান পাশে থাকা লুপটিতে সংজ্ঞায়িত ভেরিয়েবলগুলির নিজস্ব স্থানীয় স্কোপ প্রসঙ্গ রয়েছে এবং ভেরিয়েবলের পরিবর্তনগুলি লুপের বাইরে দেখা যাবে না। লুপটি লুপটি মূলত একটি সাবশেল যা শেল পরিবেশের একটি কপি পায় এবং পরিবেশের কোনও পরিবর্তন শেলের শেষে হারিয়ে যায়। এই স্ট্যাকওভারফ্লো প্রশ্নটি দেখুন

আপডেট : আমি এই গুরুত্বপূর্ণ সত্যটি উল্লেখ করতে অবহেলা করেছি যে এটির নিজের সাবসেলের সাথে লুপটি পাইপের শেষ পয়েন্ট হওয়ার কারণে হয়েছিল, আমি উত্তরে তা আপডেট করেছি।


@ জেসবিলিংস .. ঠিক আছে, এটি দুটি শেষ স্নিপেটগুলি ব্যাখ্যা করে, তবে এটি প্রথমটি ব্যাখ্যা করে না, যেখানে লুপে $ x সেট এর মান 55 হিসাবে চালিত হয় (যখন 'লুপের আওতার বাইরে)
পিটার.ও

5
@ ফ্রেড.বায়ার: এটি whileএকটি পাইপলাইনের লেজের প্রান্ত হিসাবে লুপটি চালাচ্ছে যা এটিকে একটি সাবশেলে ফেলে দেয়।
গাইকোসর

2
এখানেই বাশ প্রক্রিয়া প্রতিস্থাপন কার্যকর হয়। পরিবর্তে blah|blah|while read ..., আপনি থাকতে পারেনwhile read ...; done < <(blah|blah)
গ্লেন জ্যাকম্যান

1
@ গেকোসৌর: আমার জবাবটিতে আমি যে বিবরণ অন্তর্ভুক্ত করেছি তা পূরণ করার জন্য ধন্যবাদ।
jsbillings

1
-1 দুঃখিত তবে এই উত্তরটি ঠিক ভুল। এটি ব্যাখ্যা করে যে কীভাবে এই স্টাফটি অনেক প্রোগ্রামিং ভাষায় কাজ করে তবে শেলের সাথে না। নীচে @ গিলিস এটি সঠিকভাবে পেয়েছে।
jpc

6

অন্যান্য উত্তরে উল্লিখিত হিসাবে , পাইপলাইনের অংশগুলি সাব-শেলগুলিতে চালিত হয়, সুতরাং সেখানে করা পরিবর্তনগুলি মূল শেলের সাথে দৃশ্যমান হয় না।

যদি আমরা কেবল বাশকে বিবেচনা করি তবে cmd | { stuff; more stuff; }কাঠামো ছাড়াও আরও দুটি কার্যকারিতা রয়েছে :

  1. প্রক্রিয়া প্রতিস্থাপন থেকে ইনপুট পুনর্নির্দেশ :

    while read var ; do x=55 ; done < <(echo fred)
    echo "$x"

    কমান্ড থেকে আউটপুটটি <(...)এমনভাবে প্রদর্শিত হবে যেন এটি কোনও নামযুক্ত পাইপ।

  2. lastpipeবিকল্প, যা ksh মত ব্যাশ কাজ করে তোলে, এবং প্রধান শেল প্রক্রিয়ায় পাইপলাইন শেষ অংশ চালায়। যদিও এটি কেবলমাত্র কাজের নিয়ন্ত্রণ অক্ষম থাকলেই কাজ করে, যেমন কোনও ইন্টারেক্টিভ শেলটিতে নয়:

    bash -c '
      shopt -s lastpipe
      echo fred | while read var ; do x=55 ; done; 
      echo "$x"
    '

    অথবা

    bash -O lastpipe -c '
      echo fred | while read var ; do x=55 ; done; 
      echo "$x"
    '

প্রক্রিয়া প্রতিস্থাপন অবশ্যই ksh এবং zsh এ সমর্থিত। তবে যেহেতু তারা পাইপলাইনটির শেষ অংশটি মূল শেলটিতে যেভাবেই চালায় তাই এটিকে কার্যকরী হিসাবে ব্যবহার করা সত্যিই প্রয়োজনীয় নয়।


0
#!/bin/bash
set -x

# prepare test data.
mkdir -p ~/test_var_global
cd ~/test_var_global
echo "a"> core.1
echo "b"> core.2
echo "c"> core.3


var=0

coreFiles=$(find . -type f -name "core*")
while read -r file;
do
  # perform computations on $i
  ((var++))
done <<EOF
$coreFiles
EOF

echo $var

Result:
...
+ echo 3
3

এটা কাজ করতে পারে।

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