লিনাক্সের শেল (`sh`) এর চেয়ে আলাদাভাবে বাশ ফাইলের পুনর্নির্দেশ কীভাবে হয়?


9

আমি একটি স্ক্রিপ্ট লিখেছিলাম যা চলমান চলাকালীন ব্যবহারকারীদের স্যুইচ করে, এবং ফাইলটি পুনর্নির্দেশকে স্ট্যান্ডার্ড এ ব্যবহার করে এটি সম্পাদন করে So user-switch.shতাই ...

#!/bin/bash

whoami
sudo su -l root
whoami

এবং এটি দিয়ে চালানো bashআমার প্রত্যাশিত আচরণ দেয়

$ bash < user-switch.sh
vagrant
root

তবে, আমি যদি স্ক্রিপ্টটি দিয়ে চালিত করি তবে আমি shআলাদা আউটপুট পাই

$ sh < user-switch.sh 
vagrant
vagrant

এর bash < user-switch.shচেয়ে আলাদা আউটপুট দিচ্ছে কেন sh < user-switch.sh?

মন্তব্য:

  • ডেবিয়ান জেসি চলমান দুটি ভিন্ন বাক্সে ঘটে

1
কোনও উত্তর নয়, তবে সম্পর্কিত sudo su: unix.stackex
بدل.

1
কি / বিন / শ = ড্যাশিয়ান উপর ড্যাশ? আমি আরএইচইএল-তে পুনরায় তিরস্কার করতে পারি না যেখানে / বিন / শ = বাশ
জেফ শ্যাচলার

1
/bin/shঅন ​​(আমার অনুলিপি) দেবিয়ান হ'ল ড্যাশ, হ্যাঁ। আমি এখনও জানতাম না যে এটি এখনও ছিল। আমি এখনও অবধি বাশ আটকেছি।
popedotninja

1
ব্যাশ আচরণ পারেন কোনো নথিভুক্ত শব্দার্থবিদ্যা দ্বারা কাজ নিশ্চিত নয়।
চার্লস ডাফি

আজ কেউ আমাকে দেখিয়েছে যে আমি যে স্ক্রিপ্টটি চালাচ্ছিলাম তা কীভাবে ব্যাশ ব্যবহারের উদ্দেশ্যে তৈরি করা হয়েছে সেগুলির শব্দার্থবিজ্ঞানের লঙ্ঘন করেছে। এই প্রশ্নের বেশ কয়েকটি দারুণ উত্তর ছিল, তবে এটি উল্লেখ করা মূল্যবান যে কোনও একটিতে সম্ভবত ব্যবহারকারীদের মধ্য স্ক্রিপ্ট পরিবর্তন করা উচিত নয়। আমি মূলত user-switch.shএকটি জেনকিন্স চাকরিতে চেষ্টা করেছি এবং এটির স্ক্রিপ্ট কার্যকর হয়েছিল। জেনকিনসের বাইরে একই স্ক্রিপ্ট চালানোর ফলে বিভিন্ন ফলাফল পাওয়া যায় এবং জেনকিন্সে আমার যে আচরণ দেখেছিল তা পেতে আমি পুনর্নির্দেশের ফাইলটি শুরু করি।
popedotninja

উত্তর:


12

একটি অনুরূপ স্ক্রিপ্ট ছাড়া sudo, তবে একই রকম ফলাফল:

$ cat script.sh
#!/bin/bash
sed -e 's/^/--/'
whoami

$ bash < script.sh
--whoami

$ dash < script.sh
itvirta

এর সাথে bash, স্ক্রিপ্টের বাকী অংশটি ইনপুট হিসাবে যায় sed, এর সাথে dash, শেলটি এটি ব্যাখ্যা করে।

এগুলিতে চলছে strace: dashস্ক্রিপ্টের একটি ব্লক পড়ে (পুরো স্ক্রিপ্টটি ধরে রাখার চেয়ে এখানে আট কেবি), এবং তারপরে স্প্যান করে sed:

read(0, "#!/bin/bash\nsed -e 's/^/--/'\nwho"..., 8192) = 36
stat("/bin/sed", {st_mode=S_IFREG|0755, st_size=73416, ...}) = 0
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|...

যার অর্থ ফাইলহ্যান্ডেলটি ফাইলের শেষে, এবং sedকোনও ইনপুট দেখতে পাবে না। বাকি অংশের মধ্যে বাফার হচ্ছে dash। (স্ক্রিপ্টটি যদি 8 কেবি ব্লকের আকারের চেয়ে দীর্ঘ হয়, তবে বাকী অংশটি পড়তে হবে sed))

অন্যদিকে, বাশ শেষ কমান্ডের শেষের দিকে ফিরে যেতে চেয়েছিল:

read(0, "#!/bin/bash\nsed -e 's/^/--/'\nwho"..., 36) = 36
stat("/bin/sed", {st_mode=S_IFREG|0755, st_size=73416, ...}) = 0
...
lseek(0, -7, SEEK_CUR)                  = 29
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|...

যদি পাইপ থেকে ইনপুটটি এখানে আসে তবে:

$ cat script.sh | bash

রিপাইন্ডিং করা যায় না, যেহেতু পাইপ এবং সকেটগুলি অনুসন্ধানযোগ্য নয়। এই ক্ষেত্রে, বাশ পড়ার বিষয়টি এড়াতে একবারে একটি অক্ষর ইনপুট পড়তে ফিরে যায় । ( fd_to_buffered_stream()ইনinput.c ) প্রতিটি বাইটের জন্য একটি সম্পূর্ণ সিস্টেম কল করা নীতিগতভাবে খুব কার্যকর নয়। অনুশীলনে, আমি মনে করি না যে পাঠাগুলি তুলনা করে একটি দুর্দান্ত ওভারহেড হবে যেমন শেলটি বেশিরভাগ ক্ষেত্রে পুরো নতুন প্রক্রিয়া তৈরি করে জড়িত।

অনুরূপ পরিস্থিতি হ'ল:

echo -e 'foo\nbar\ndoo' | bash -c 'read a; head -1'

সাব-শেলটি নিশ্চিত করতে হবে যে readকেবল প্রথম নতুন headলাইনটি পড়েছে, যাতে পরের লাইনটি দেখতে পায়। ( dashএটিও এর সাথে কাজ করে ))


অন্য কথায়, বাশ একই উত্সটি স্ক্রিপ্টের জন্য এবং এটি থেকে সম্পাদিত আদেশগুলির জন্য সমর্থন করতে অতিরিক্ত দৈর্ঘ্যে যায়। dashনা। দ্য zsh, এবং ksh93প্যাকেজড ডাবিয়ান এই বিষয়ে বাশের সাথে যান।


1
সত্যি বলতে, আমি কিছুটা অবাক হয়েছি যা কাজ করে।
ইল্কাচ্চু

মহান উত্তরের জন্য ধন্যবাদ! আমি উভয় কমান্ড straceপরে ব্যবহার করব এবং ফলাফলগুলি তুলনা করব । যদিও আমি এই পদ্ধতির ব্যবহার করতে পারি নি।
popedotninja

2
হ্যাঁ, প্রশ্ন পড়া আমার প্রতিক্রিয়া বিস্ময় ছিল এটি করে ব্যাশ সঙ্গে কাজ - আমি এটা কিছু যেমন দূরে দায়ের যে স্পষ্টভাবে কাজ না করতেন। আমার ধারণা আমি ঠিক অর্ধেক ঠিক ছিল :)
hobbs

12

শেলটি স্ট্যান্ডার্ড ইনপুট থেকে স্ক্রিপ্টটি পড়ছে। স্ক্রিপ্টের ভিতরে, আপনি একটি কমান্ড চালান যা মানক ইনপুটও পড়তে চায় wants কোন ইনপুট কোথায় যাচ্ছে? আপনি নির্ভরযোগ্যভাবে বলতে পারবেন না

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

স্ক্রিপ্টের কোনও কমান্ড যদি শেলটি থেকে স্ক্রিপ্টটি পড়ছে একই ফাইল বিবরণকারী থেকে পড়ার চেষ্টা করে, তবে কমান্ডটি এটি পড়ার শেষ অংশের পরে যা আসবে তা খুঁজে পাবে। এই অবস্থানটি অপ্রত্যাশিত: এটি শেলটি কী পরিমাণ আকার বেছে নিয়েছে তার উপর নির্ভর করে এবং এটি কেবল শেল এবং এর সংস্করণে নয় কেবল মেশিনের কনফিগারেশন, উপলব্ধ মেমরি ইত্যাদির উপর নির্ভর করে can

কমান্ডটি কার্যকর করার আগে বাশ স্ক্রিপ্টে একটি কমান্ডের উত্স কোডের শেষের দিকে চেষ্টা করে। এটি এমন কোনও জিনিস নয় যা আপনি বিশ্বাস করতে পারেন, কেবলমাত্র অন্যান্য শেলগুলি এটি করে না বলেই নয়, তবে এটি কেবলমাত্র শেল একটি নিয়মিত ফাইল থেকে পড়তে থাকলে কাজ করে। যদি শেলটি কোনও পাইপ (উদাহরণস্বরূপ ssh remote-host.example.com <local-script-file.sh) থেকে পড়তে থাকে তবে যে ডেটাটি পড়েছে তা পঠিত এবং অপঠিত হতে পারে না।

আপনি যদি স্ক্রিপ্টের কোনও কমান্ডে ইনপুটটি পাস করতে চান, আপনার সাধারণত স্পষ্টভাবে এটি করা দরকার, সাধারণত একটি নথির সাথে । (এখানে ডকুমেন্টটি সাধারণত মাল্টি-লাইন ইনপুট জন্য সর্বাধিক সুবিধাজনক, তবে যে কোনও পদ্ধতি এটি করবে)) আপনি যে কোডটি লিখেছেন তা কেবলমাত্র কয়েকটি শেলের মধ্যে কাজ করে, কেবলমাত্র যদি স্ক্রিপ্টটি নিয়মিত ফাইল থেকে শেলের ইনপুট হিসাবে পাস হয়; আপনি যদি প্রত্যাশা করেছিলেন যে দ্বিতীয়টি whoamiইনপুট হিসাবে পাস হবে sudo …, আবার মনে করুন, বেশিরভাগ সময় স্ক্রিপ্টটি শেলের স্ট্যান্ডার্ড ইনপুটটিতে পাস হয় না।

#!/bin/bash
whoami
sudo su -l root <<'EOF'
whoami
EOF

এই দশকে নোট করুন, আপনি ব্যবহার করতে পারেন sudo -i root। দৌড়ানো sudo suঅতীতের একটি হ্যাক।

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