বাশ সহ কোনও ফাইল থেকে লাইনগুলি পড়া: বনাম কিছুক্ষণের জন্য


36

আমি কোনও পাঠ্য ফাইলটি পড়ার চেষ্টা করছি এবং প্রতিটি লাইন দিয়ে বাশ স্ক্রিপ্ট ব্যবহার করে কিছু করব।

সুতরাং, আমার কাছে একটি তালিকা রয়েছে যা দেখতে এরকম দেখাচ্ছে:

server1
server2
server3
server4

আমি ভেবেছিলাম কিছুক্ষণ লুপ ব্যবহার করে এটির উপর দিয়ে লুপ করতে পারি, এরকম:

while read server; do
  ssh $server "uname -a"
done < /home/kenny/list_of_servers.txt

লুপটি 1 রান পরে থামবে, এইভাবে কেবল uname -aসার্ভার 1 এ চলছে

তবে বিড়াল ব্যবহার করে লুপের সাহায্যে এটি দুর্দান্ত কাজ করে:

for server in $(cat /home/kenny/list_of_servers.txt) ; do
  ssh $server "uname -a"
done

আমার কাছে আরও বেশি বিস্মিত হওয়ায় এটি কাজ করে:

while read server; do
  echo $server
done < /home/kenny/list_of_servers.txt

আমার প্রথম উদাহরণটি প্রথম পুনরাবৃত্তির পরে কেন থামবে?

উত্তর:


25

forলুপ এখানে জরিমানা। তবে নোট করুন যে ফাইলটি মেশিনের নামগুলি ধারণ করে কারণ এতে কোনও শ্বেতক্ষেত্রের অক্ষর বা গ্লোববিং অক্ষর নেই। সাধারণ for x in $(cat file); do …রেখাগুলির উপরে পুনরাবৃত্তি করার জন্য কাজ করে না file, কারণ শেলটি প্রথমে cat fileযে কোনও জায়গাতেই সাদা স্থান রয়েছে কমান্ড থেকে আউটপুট বিভক্ত করে এবং তারপরে প্রতিটি শব্দকে \[?*গ্লোব প্যাটার্ন হিসাবে বিবেচনা করে তাই আরও প্রসারিত করা হয়। আপনি for x in $(cat file)যদি এতে কাজ করেন তবে আপনি নিরাপদ করতে পারেন:

set -f
IFS='
'
for x in $(cat file); do 

সম্পর্কিত পড়া: নামে ফাঁকা ফাইল দিয়ে লুপিং? ; ব্যাশে ভেরিয়েবল থেকে লাইনে কীভাবে পড়তে পারি? ; পরিবর্তে কেন while IFS= readএত ঘন ঘন ব্যবহার করা হয় IFS=; while read..? মনে রাখবেন যে ব্যবহার while readকরার সময়, লাইনগুলি পড়ার নিরাপদ বাক্য গঠন while IFS= read -r line; do …

এখন আসুন আপনার while readপ্রয়াসে কী ভুল হয় তা ফিরে আসুন । সার্ভার তালিকা ফাইল থেকে পুনঃনির্দেশ পুরো লুপের জন্য প্রযোজ্য। সুতরাং যখন sshরান, তার মান ইনপুট আসে ফাইল থেকে। Ssh ক্লায়েন্ট জানতে পারে না যে কখন দূরবর্তী অ্যাপ্লিকেশনটি এর স্ট্যান্ডার্ড ইনপুট থেকে পড়তে চাইতে পারে। সুতরাং যত তাড়াতাড়ি ssh ক্লায়েন্ট কিছু ইনপুট লক্ষ্য করে, এটি সেই ইনপুটটি দূরবর্তী দিকে প্রেরণ করে। সেখানকার ssh সার্ভারটি তখন এটি ইনপুটটি রিমোট কমান্ডে ফিড করতে প্রস্তুত। আপনার ক্ষেত্রে, রিমোট কমান্ডটি কোনও ইনপুট কখনই পড়ে না, তাই ডেটাটি ফেলে দেওয়া হয়, তবে ক্লায়েন্ট পক্ষ এটি সম্পর্কে কিছুই জানে না। কাজের সাথে আপনার প্রচেষ্টা echoকারণ echoকোনও ইনপুট কখনই পড়ে না, এটি এর স্ট্যান্ডার্ড ইনপুটটি একা ফেলে দেয়।

আপনি এড়াতে পারেন এমন কয়েকটি উপায়। আপনি -nবিকল্পটি সহ এসএসএসকে স্ট্যান্ডার্ড ইনপুট থেকে না পড়তে বলতে পারেন ।

while read server; do
  ssh -n $server "uname -a"
done < /home/kenny/list_of_servers.txt

-nআসলে বিকল্প বলে sshথেকে তার ইনপুট পুনর্নির্দেশ করতে /dev/null। আপনি শেল স্তরে এটি করতে পারেন এবং এটি কোনও কমান্ডের জন্য কাজ করবে।

while read server; do
  ssh $server "uname -a" </dev/null
done < /home/kenny/list_of_servers.txt

এড়ানোর SSH এর ইনপুট ফাইল থেকে আসছে একটি প্রলুব্ধকর পদ্ধতির উপর ফেরৎ করা হয় readকমান্ড প্রয়োগ করুন: while read server </home/kenny/list_of_servers.txt; do …। এটি কাজ করবে না, কারণ এটি প্রতিবার readকমান্ড কার্যকর হওয়ার সাথে সাথে ফাইলটি আবার খোলার কারণ হয় (সুতরাং এটি ফাইলটির প্রথম লাইনটি বার বার পড়তে পারে)। লুপটির সময় পুনঃনির্দেশটি পুরোপুরি হওয়া দরকার যাতে লুপের সময়কালের জন্য ফাইলটি একবার খোলায়।

সাধারণ সমাধান হ'ল স্ট্যান্ডার্ড ইনপুট ব্যতীত কোনও ফাইল বর্ণনাকারীর লুপকে ইনপুট সরবরাহ করা। শেলটিতে ফেরি ইনপুট এবং একটি বর্ণনাকারী সংখ্যার থেকে অন্য বর্ণনায় আউটপুট তৈরি হয়। এখানে, আমরা ফাইল বর্ণনাকারী 3 এ ফাইলটি খুলি এবং ফাইল বিবরণকারী 3 থেকে readকমান্ডের স্ট্যান্ডার্ড ইনপুটটি পুনর্নির্দেশ করি The

while read server <&3; do
  ssh $server "uname -a"
done 3</home/kenny/list_of_servers.txt

ব্যাশে, readকমান্ডের একটি পৃথক ফাইল বর্ণনাকারী থেকে পড়ার জন্য একটি নির্দিষ্ট বিকল্প রয়েছে, যাতে আপনি লিখতে পারেন read -u3 server

সম্পর্কিত পড়া: ফাইল বর্ণনাকারী এবং শেল স্ক্রিপ্টিং ; আপনি কখন অতিরিক্ত ফাইল বর্ণনাকারী ব্যবহার করবেন?


5
ম্যান, এই স্ট্যাকেক্সচেঞ্জটি সার্ভারফল্ট থেকে আলাদা। এখানকার লোকেরা কেবল উত্তরই দেয় না, শিক্ষিতও করে way অনেক ধন্যবাদ.
কেনি রাশচেয়ার্ট

26

আপনার ব্যবহার করা উচিত while, নাfor । এই জাতীয় লুপে স্ট্যান্ডার্ড ইনপুট গিলে কমান্ডগুলি এড়ানোর উপায়টি কেবল অন্য কোনও ফাইল বর্ণনাকারী ব্যবহার করা :

while read -u 9 server; do
  ssh $server "uname -a"
done 9< /home/kenny/list_of_servers.txt

অধিক বিবরণের জন্য help [r]ead( সত্যিই ) এবং অন্য নিবন্ধ কেন ব্যাখ্যা


1
আকর্ষণীয়, আমি আগে কখনও ফাইল বর্ণনাকারী ব্যবহার করি নি। কী -uপতাকা না? আমি কোন ম্যান পৃষ্ঠাতে এটি সন্ধান করার কথা তা নিশ্চিত নই।
কেনি রাসচেয়ার্ট

পঠন কমান্ডটি শেল ব্যাশের অংশ, সুতরাং এটি পঠিত অনুচ্ছেদে "শেল বিল্টিন কম্যান্ডস" বিভাগে ব্যাশের ম্যান পৃষ্ঠাতে রয়েছে। আপনি "-u এফডি পড়ুন ইনপুট ফাইল বিবরণকারী এফডি থেকে পাবেন।" এই অনুচ্ছেদে
f4m8

6
বিকল্পভাবে help read- শেল বিল্টিনগুলির জন্য পৃষ্ঠাগুলির helpসমতুল্য manপ্রাপ্তির আদেশ।
l0b0

22

আপনার প্রথম কোডটি sshএসটিডিএন থেকে "চুরি" করবে while। এটি এড়ানোর -nজন্য বিকল্প যুক্ত করুন ssh। থেকে man ssh:

-n     Redirects stdin from /dev/null (actually, prevents reading from stdin).

ঠিক আছে, কোনও ধারণা পেয়েছেন কেন লুপের জন্য এটি ঘটে না?
কেনি রাশচেয়ার্ট

7
কারণ forলুপটি ইনপুট হিসাবে নয়, প্যারামিটার হিসাবে ডেটা গ্রহণ করে।
manatwork

1
আপনি, স্যার, একটি সজ্জন এবং একটি পণ্ডিত.
কেনি রাসচেয়ার্ট

0

ডিফল্ট স্ট্যান্ডার্ড ইনপুট হ্যান্ডলিং sshযখন লুপ থেকে অবশিষ্ট রেখাটি নিষ্কাশন করে।

এই সমস্যাটি এড়ানোর জন্য, সমস্যাযুক্ত কমান্ড যেখান থেকে স্ট্যান্ডার্ড ইনপুট পড়ে তা পরিবর্তন করুন। কমান্ডে যদি কোনও স্ট্যান্ডার্ড ইনপুট পাস করার প্রয়োজন না হয় তবে বিশেষ /dev/nullডিভাইস থেকে স্ট্যান্ডার্ড ইনপুট পড়ুন ।

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