দ্রষ্টব্য: @ jw013 নীচের মন্তব্যে নিম্নলিখিত অসমর্থিত আপত্তি তোলে :
ডাউনভোটটি হ'ল স্ব-সংশোধনকারী কোডটি সাধারণত খারাপ অভ্যাস হিসাবে বিবেচিত হয়। ছোট ছোট সমাবেশ কর্মসূচির পুরানো দিনগুলিতে শর্তযুক্ত শাখা হ্রাস এবং কার্যকারিতা উন্নত করার জন্য একটি চতুর উপায় ছিল, কিন্তু আজকাল সুরক্ষা ঝুঁকিগুলির সুবিধাগুলি ছাড়িয়ে যায়। স্ক্রিপ্টটি চালানো ব্যবহারকারীর স্ক্রিপ্টে লেখার সুযোগ না থাকলে আপনার পদ্ধতির কাজ হবে না।
আমি যে ইশারা দ্বারা তার নিরাপত্তা আপত্তি বললেন কোনো বিশেষ অনুমতির হয় শুধুমাত্র একবার প্রয়োজনীয় প্রতি ইনস্টল / আপডেট অর্ডার কর্ম ইনস্টল / আপডেট স্ব-ইনস্টল করার যা আমি ব্যক্তিগতভাবে বেশ নিরাপদ কল করবে - স্ক্রিপ্ট। আমি তাকে man sh
অনুরূপ উপায়ে অনুরূপ লক্ষ্য অর্জনের একটি রেফারেন্সের দিকেও ইঙ্গিত করেছিলাম । আমি সেই সময়ে এটি উল্লেখ করে বিরক্ত করি নি যে সুরক্ষার ত্রুটি বা অন্যথায় সাধারণত যে উত্তরহীন অনুশীলনগুলি আমার উত্তরে উপস্থাপিত হতে পারে বা না হতে পারে, সেগুলি আমার জবাবের চেয়ে তারা সম্ভবত প্রশ্নটিতেই মূলত:
আমি কীভাবে শেবাং সেট আপ করতে পারি যাতে স্ক্রিপ্টটি /path/to/script.sh হিসাবে চালানো সর্বদা PATH এ উপলব্ধ Zsh ব্যবহার করে?
সন্তুষ্ট নন, @ jw013 কমপক্ষে দু'দফা ভুল বক্তব্য দিয়ে তাঁর এখনও অসমর্থিত যুক্তিটি প্রকাশ করে আপত্তি জানাতে থাকলেন :
আপনি একটি ফাইল ব্যবহার করেন, দুটি ফাইল নয়। [ man sh
রেফারেন্সড]
প্যাকেজ একটি ফাইল অন্য ফাইল পরিবর্তন হয়েছে। আপনার নিজের মধ্যে ফাইল পরিবর্তন করতে হবে। এই দুটি ক্ষেত্রে পৃথক পার্থক্য রয়েছে। একটি ফাইল যা ইনপুট নেয় এবং আউটপুট উত্পাদন করে তা ঠিক। একটি এক্সিকিউটেবল ফাইল যা এটি চলার সাথে সাথে নিজেকে বদলে দেয় তা সাধারণত একটি খারাপ ধারণা। আপনি যে উদাহরণটি নির্দেশ করেছেন তা তা করে না।
প্রথম অবস্থানে:
কেবলমাত্র এক্সিকিউটেবল কোনো কোড এক্সিকিউটেবল শেল স্ক্রিপ্ট IS #!
নিজেকে
(যদিও এমনকি #!
নেই আনুষ্ঠানিকভাবে অনির্দিষ্ট )
{ cat >|./file
chmod +x ./file
./file
} <<-\FILE
#!/usr/bin/sh
{ ${l=lsof -p} $$
echo "$l \$$" | sh
} | grep \
"COMMAND\|^..*sh\| [0-9]*[wru] "
#END
FILE
##OUTPUT
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
file 8900 mikeserv txt REG 0,33 774976 2148676 /usr/bin/bash
file 8900 mikeserv mem REG 0,30 2148676 /usr/bin/bash (path dev=0,33)
file 8900 mikeserv 0r REG 0,35 108 15496912 /tmp/zshUTTARQ (deleted)
file 8900 mikeserv 1u CHR 136,2 0t0 5 /dev/pts/2
file 8900 mikeserv 2u CHR 136,2 0t0 5 /dev/pts/2
file 8900 mikeserv 255r REG 0,33 108 2134129 /home/mikeserv/file
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
sh 8906 mikeserv txt REG 0,33 774976 2148676 /usr/bin/bash
sh 8906 mikeserv mem REG 0,30 2148676 /usr/bin/bash (path dev=0,33)
sh 8906 mikeserv 0r FIFO 0,8 0t0 15500515 pipe
sh 8906 mikeserv 1w FIFO 0,8 0t0 15500514 pipe
sh 8906 mikeserv 2u CHR 136,2 0t0 5 /dev/pts/2
{ sed -i \
'1c#!/home/mikeserv/file' ./file
./file
sh -c './file ; echo'
grep '#!' ./file
}
##OUTPUT
zsh: too many levels of symbolic links: ./file
sh: ./file: /home/mikeserv/file: bad interpreter: Too many levels of symbolic links
#!/home/mikeserv/file
শেল স্ক্রিপ্টটি কেবল একটি পাঠ্য ফাইল - এটির যে কোনও প্রভাব ফেলতে হলে এটি অন্য কার্যকরযোগ্য ফাইলের দ্বারা পড়তে হবে, এর নির্দেশাবলীর পরে অন্য নির্বাহযোগ্য ফাইল দ্বারা ব্যাখ্যা করা যেতে পারে, শেষ পর্যন্ত অন্যান্য এক্সিকিউটেবল ফাইলের পরে তার ব্যাখ্যাটি কার্যকর করে শেল স্ক্রিপ্ট এটা সম্ভব নয় একটি শেল স্ক্রিপ্ট ফাইলের সঞ্চালনের জন্য কম দুটি ফাইলের জড়িত। zsh
নিজস্ব সংকলকটিতে একটি সম্ভাব্য ব্যতিক্রম রয়েছে , তবে এটির সাথে আমার খুব কম অভিজ্ঞতা আছে এবং এটি এখানে কোনও উপায়ে উপস্থাপন করা হয় না।
একটি শেল স্ক্রিপ্টের হ্যাশবাং অবশ্যই এটির উদ্দেশ্যে করা দোভাষীকে ইঙ্গিত করতে পারে বা অপ্রাসঙ্গিক হিসাবে ফেলে দেওয়া উচিত।
শেল পার্স এবং তার ইনপুট ব্যাখ্যা দুটি মৌলিক মোড আছে: পারেন তার বর্তমান ইনপুট একটি সংজ্ঞা করা হয় <<here_document
বা এটি একটি সংজ্ঞা করা হয় { ( command |&&|| list ) ; } &
- অন্য কথায়, শেল পারেন ব্যাখ্যা করে একটি টোকেন কমান্ড একবার এটা পড়েছেন এটি চালানো উচিত একটি বিভেদক হিসাবে কোনও ফাইল তৈরি করতে এবং অন্য কমান্ডের জন্য ফাইল বর্ণনাকারীতে এটি ম্যাপ করার নির্দেশাবলী হিসাবে বা এটাই.
শেলটি কার্যকর করতে আদেশগুলি ব্যাখ্যা করার সময় সংরক্ষিত শব্দের সংকলনে টোকেনগুলি সীমানা করে । যখন প্রযোজ্য - - বা ক্লোজিং টোকেনের মতোই শেল খোলা টোকেন এটা যেমন একটি newline যেমন কমান্ড তালিকায় পড়তে চালিয়ে যেতে হবে যতক্ষণ না তালিকা পারেন টোকেন একটি ক্লোজিং দ্বারা সীমায়িত করা হয় encounters যখন })
জন্য ({
মৃত্যুদন্ড আগে।
শেল একটি সাধারণ কমান্ড এবং একটি যৌগিক কমান্ডের মধ্যে পার্থক্য করে । যৌগ কমান্ড কমান্ড যে মৃত্যুদন্ড সামনে পড়া করা আবশ্যক সেট, কিন্তু শেল সঞ্চালন নেই $expansion
তার উপাদান কোনো সহজ কমান্ড পর্যন্ত এটি একেলা প্রতিটি এক সঞ্চালন করে।
সুতরাং, নিম্নলিখিত উদাহরণে, ;semicolon
সংরক্ষিত শব্দগুলি পৃথক সরল কমান্ডের সীমানা নির্ধারণ করে যেখানে \newline
অরক্ষিত অক্ষর দুটি যৌগিক কমান্ডের মধ্যে সীমাবদ্ধ করে:
{ cat >|./file
chmod +x ./file
./file
} <<-\FILE
#!/usr/bin/sh
echo "simple command ${sc=1}" ;\
: > $0 ;\
echo "simple command $((sc+2))" ;\
sh -c "./file && echo hooray"
sh -c "./file && echo hooray"
#END
FILE
##OUTPUT
simple command 1
simple command 3
hooray
এটি নির্দেশিকাগুলির সরলীকরণ। আপনি শেল-বিল্টিনস, সাবশেলস, বর্তমান পরিবেশ এবং ইত্যাদি বিবেচনা করলে এটি আরও জটিল হয়ে যায় তবে আমার উদ্দেশ্যগুলির জন্য এখানে যথেষ্ট।
এবং বিল্ট-ইনগুলি এবং কমান্ড-তালিকাগুলির কথা বলতে গেলে a function() { declaration ; }
কেবল একটি সাধারণ কমান্ডের জন্য একটি যৌগিক কমান্ড নির্ধারণের একটি উপায়। শেলটি অবশ্যই $expansions
ডিক্লেয়ারেশন স্টেটমেন্টে নিজেই কোনও সম্পাদন করতে পারে না <<redirections>
- অন্তর্ভুক্ত করতে - তবে এর পরিবর্তে সংজ্ঞাটি একটি একক, আক্ষরিক স্ট্রিং হিসাবে সংরক্ষণ করতে হবে এবং ডাকা হলে এটি একটি বিশেষ শেল হিসাবে নির্মিত হবে built
সুতরাং এক্সিকিউটেবল শেল স্ক্রিপ্টে ঘোষিত শেল ফাংশনটি শাবকের স্মৃতিটিকে তার আক্ষরিক স্ট্রিং ফর্মের মধ্যে সংরক্ষণ করা হয় - এখানে সংযুক্ত-ডকুমেন্টগুলিকে ইনপুট হিসাবে অন্তর্ভুক্ত করা যায় না - এবং যতবার শেল বিল্ট- বলা হয় ততবার তার উত্স ফাইলের স্বাধীনভাবে সম্পাদন করা হয়- যতক্ষণ শেলের বর্তমান পরিবেশ স্থায়ী হয় ততক্ষণ।
পুনঃনির্দেশ অপারেটর <<
এবং <<-
উভয়ই কমান্ডের ইনপুটটিতে শেল ইনপুট ফাইলে থাকা লাইনের পুনঃনির্দেশের অনুমতি দেয়, যা এখানে নথি হিসাবে পরিচিত ।
এখানে নথি একটি কথাও আগামী পর শুরু হয় হিসাবে গণ্য হইবে \newline
এবং যতক্ষণ সেখানে মাত্র ধারণকারী একটি লাইন চলতে বিভেদক এবং \newline
, কোন সঙ্গে [:blank:]
মাঝে সে। তারপরে পরবর্তী এখানে-নথিটি শুরু হয়, যদি একটি থাকে। ফর্ম্যাটটি নিম্নরূপ:
[n]<<word
here-document
delimiter
... যেখানে al n
চ্ছিক ফাইল বর্ণনাকারী নম্বর উপস্থাপন করে। যদি নম্বরটি বাদ দেওয়া হয় তবে এখানে-নথিটি স্ট্যান্ডার্ড ইনপুট (ফাইল বর্ণনাকারী 0) বোঝায় ।
for shell in dash zsh bash sh ; do sudo $shell -c '
{ readlink /proc/self/fd/3
cat <&3
} 3<<-FILE
$0
FILE
' ; done
#OUTPUT
pipe:[16582351]
dash
/tmp/zshqs0lKX (deleted)
zsh
/tmp/sh-thd-955082504 (deleted)
bash
/tmp/sh-thd-955082612 (deleted)
sh
দেখেন তো? শেলের উপরের প্রতিটি শেলের জন্য একটি ফাইল তৈরি করে এটি একটি ফাইল বর্ণনাকারীতে মানচিত্র করে। ইন zsh, (ba)sh
শেল মধ্যে একজন নিয়মিত ফাইল তৈরি করে /tmp
, আউটপুট ডাম্প, একটি বর্ণনাকারী তা মানচিত্র, তারপর মুছে ফেলে /tmp
ফাইল যাতে বর্ণনাকারী এর কার্নেল এর অনুলিপি যে সব থাকে। dash
এই সমস্ত বাজে কথা এড়িয়ে চলে এবং |pipe
পুনঃনির্দেশ লক্ষ্যকে <<
লক্ষ্য করে একটি অনামী ফাইলের মধ্যে তার আউটপুট প্রসেসিংটিকে কেবল ড্রপ করে ।
এটি তোলে dash
:
cmd <<HEREDOC
$(cmd)
HEREDOC
কার্যত সমান bash
:
cmd <(cmd)
যখন dash
এর বাস্তবায়ন অন্তত POSIXly পোর্টেবল।
যা বিভিন্ন ফাইল তৈরি করে
নীচের উত্তরে আমি যখন করি তখন:
{ cat >|./file
chmod +x ./file
./file
} <<\FILE
#!/usr/bin/sh
_fn() { printf '#!' ; command -v zsh ; cat
} <<SCRIPT >$0
[SCRIPT BODY]
SCRIPT
_fn ; exec $0
FILE
নিম্নলিখিত ঘটে:
আমি প্রথম cat
যাই হোক না কেন ফাইল শেল জন্য তৈরি বিষয়বস্তু FILE
মধ্যে ./file
, এটা এক্সিকিউটেবল করুন, তারপরে এটি চালানো।
কার্নেলটি ব্যাখ্যা করে #!
এবং নির্ধারিত /usr/bin/sh
একটি <read
ফাইল বর্ণনাকারীর সাথে কল করে ./file
।
sh
যৌগিক কমান্ডটি শুরু _fn()
এবং শেষ হওয়া মিশ্রণে একটি স্ট্রিং মানচিত্র করে SCRIPT
।
যখন _fn
বলা হয়, sh
প্রথম তারপর একটি বর্ণনাকারী ফাইল সংজ্ঞায়িত মানচিত্র ব্যাখ্যা করতে হবে <<SCRIPT...SCRIPT
আগে invoking _fn
বিল্ট ইন ইউটিলিটি একটি বিশেষ হিসাবে কারণ SCRIPT
হল _fn
এর<input.
স্ট্রিং আউটপুট দ্বারা printf
এবং command
আউট লেখা হয় _fn
'র মান-আউট >&1
- যা বর্তমান শেল এর থেকে আপনাকে পুনঃনির্দেশিত করা হয় ARGV0
- বা $0
।
cat
এর <&0
স্ট্যান্ডার্ড-ইনপুট ফাইল-বর্ণনাকারীকে সংযুক্ত করে - SCRIPT
- >
কাটা বর্তমান শেলের ARGV0
আর্গুমেন্টের উপর, বা $0
।
এর ইতিমধ্যে পঠিত বর্তমান যৌগিক কমান্ডটি সম্পূর্ণ করা , sh exec
এক্সিকিউটেবল - এবং সদ্য পুনর্লিখন - $0
যুক্তি।
সেই সময় থেকে ./file
ডেকে আনা হয় যতক্ষণ না এর অন্তর্ভুক্ত নির্দেশাবলী নির্দিষ্ট করে যে এটি exec
আবার ডি হওয়া উচিত , sh
এটি একবারে একটি একক যৌগ কমান্ডে পড়ে যখন এটি কার্যকর করে, যখন ./file
নিজেই নতুন বিষয়বস্তু আনন্দের সাথে গ্রহণ না করে কিছুই করে না । প্রকৃতপক্ষে কর্মরত ফাইলগুলি হ'ল/usr/bin/sh, /usr/bin/cat, /tmp/sh-something-or-another.
ধন্যবাদ, সব পরে
সুতরাং যখন @ jw013 নির্দিষ্ট করে:
একটি ফাইল যা ইনপুট নেয় এবং আউটপুট উত্পাদন করে তা ঠিক ...
... এই উত্তরের ভ্রান্ত সমালোচনার মধ্যেও তিনি অজ্ঞাতসারে এখানে ব্যবহৃত একমাত্র পদ্ধতিটি ক্ষমা করছেন, যা মূলত ন্যায়বিচারের জন্য কাজ করে:
cat <new_file >old_file
উত্তর
এখানে সমস্ত উত্তর ভাল তবে এগুলির কোনওোটাই পুরোপুরি সঠিক নয়। প্রত্যেকে দাবি করছে যে আপনি গতিশীল এবং স্থায়ীভাবে আপনার পথে যেতে পারবেন না #!bang
। এখানে একটি পাথ স্বতন্ত্র শেবাং স্থাপনের একটি বিক্ষোভ রয়েছে:
ডেমো
{ cat >|./file
chmod +x ./file
./file
} <<\FILE
#!/usr/bin/sh
_rewrite_me() { printf '#!' ; command -v zsh
${out+cat} ; ${out+:} . /dev/fd/0 >&2
} <<\SCRIPT >|${out-/dev/null}
printf "
\$0 :\t$0
lines :\t$((c=$(wc -l <$0)))
!bang :\t$(sed 1q "$0")
shell :\t"$(printf `ps -o args= -p $$`)\\n\\n
sed -n "1,2{=;p};$((c-1)),\${=;p}" "$0" |
sed -e 'N;s/\n/ >\t/' -e 4a\\...
SCRIPT
_rewrite_me ; out=$0 _rewrite_me ; exec $0
FILE
আউটপুট
$0 : ./file
lines : 13
!bang : #!/usr/bin/sh
shell : /usr/bin/sh
1 > #!/usr/bin/sh
2 > _rewrite_me() { printf '#!' ; command -v zsh
...
12 > SCRIPT
13 > _rewrite_me ; out=$0 _rewrite_me ; exec $0
$0 : /home/mikeserv/file
lines : 8
!bang : #!/usr/bin/zsh
shell : /usr/bin/zsh
1 > #!/usr/bin/zsh
2 > printf "
...
7 > sed -n "1,2{=;p};$((c-1)),\${=;p}" "$0" |
8 > sed -e 'N;s/\n/ >\t/' -e 4a\\...
দেখেন তো? আমরা কেবল স্ক্রিপ্টটিকে নিজেই ওভাররাইট করি। এবং এটি git
সিঙ্কের পরে কেবল একবারই ঘটে । সেই দিক থেকে এটি #! ব্যাং লাইনে সঠিক পথ পেয়েছে।
এখন প্রায় সেখানে প্রায় পুরোপুরি ঝাঁকুনি আছে। নিরাপদে এটি করতে আপনার প্রয়োজন:
শীর্ষে সংজ্ঞায়িত একটি ফাংশন এবং নীচে ডাকা হয় যা লেখাটি করে। এইভাবে আমরা মেমরিতে আমাদের প্রয়োজনীয় সমস্ত জিনিস সঞ্চয় করি এবং এটি লেখা শুরু করার আগে পুরো ফাইলটি অবশ্যই পঠিত রয়েছে তা নিশ্চিত করি।
পথটি কী হওয়া উচিত তা নির্ধারণের কিছু উপায়। command -v
এটির জন্য বেশ ভাল।
বংশগতরা সত্যই সহায়তা করে কারণ তারা প্রকৃত ফাইল। এর মধ্যে তারা আপনার স্ক্রিপ্ট সংরক্ষণ করবে। আপনি স্ট্রিং ব্যবহার করতে পারেন তবে ...
আপনাকে নিশ্চিত করতে হবে যে শেলটি যে কমান্ডটিতে পড়েছে তা একই কমান্ড তালিকায় আপনার স্ক্রিপ্টটিকে যেটি কার্যকর করে তার ওভাররাইট করে।
দেখুন:
{ cat >|./file
chmod +x ./file
./file
} <<\FILE
#!/usr/bin/sh
_rewrite_me() { printf '#!' ; command -v zsh
${out+cat} ; ${out+:} . /dev/fd/0 >&2
} <<\SCRIPT >|${out-/dev/null}
printf "
\$0 :\t$0
lines :\t$((c=$(wc -l <$0)))
!bang :\t$(sed 1q "$0")
shell :\t"$(printf `ps -o args= -p $$`)\\n\\n
sed -n "1,2{=;p};$((c-1)),\${=;p}" "$0" |
sed -e 'N;s/\n/ >\t/' -e 4a\\...
SCRIPT
_rewrite_me ; out=$0 _rewrite_me
exec $0
FILE
লক্ষ্য করুন আমি exec
কমান্ডটি কেবল একটি লাইনে সরিয়েছি। এখন:
#OUTPUT
$0 : ./file
lines : 14
!bang : #!/usr/bin/sh
shell : /usr/bin/sh
1 > #!/usr/bin/sh
2 > _rewrite_me() { printf '#!' ; command -v zsh
...
13 > _rewrite_me ; out=$0 _rewrite_me
14 > exec $0
আমি আউটপুটটির দ্বিতীয়ার্ধটি পাই না কারণ স্ক্রিপ্টটি পরবর্তী কমান্ডে পড়তে পারে না। তবুও, কারণ একমাত্র আদেশটি অনুপস্থিত ছিল শেষ:
cat ./file
#!/usr/bin/zsh
printf "
\$0 :\t$0
lines :\t$((c=$(wc -l <$0)))
!bang :\t$(sed 1q "$0")
shell :\t"$(printf `ps -o args= -p $$`)\\n\\n
sed -n "1,2{=;p};$((c-1)),\${=;p}" "$0" |
sed -e 'N;s/\n/ >\t/' -e 4a\\...
স্ক্রিপ্টটি যেমনটি হওয়া উচিত ছিল তেমনটি এসেছে - বেশিরভাগ কারণ এটি সমস্তই হেরডোকের মধ্যে ছিল - তবে আপনি যদি এটি ঠিকভাবে পরিকল্পনা না করেন তবে আপনি আপনার ফাইল স্ট্রিমটি কেটে ফেলতে পারবেন, যা আমার উপরে ঘটেছে।
env
যে / বিন এবং / ইউএসআর / বিন উভয়ই নেই?which -a env
নিশ্চিত করার চেষ্টা করুন।