নতুন প্রশ্নের জন্য, এই স্ক্রিপ্টটি কাজ করে:
#!/bin/bash
f() { for i in $(seq "$((RANDOM % 3 ))"); do
echo;
done; return $((RANDOM % 256));
}
exact_output(){ out=$( $1; ret=$?; echo x; exit "$ret" );
unset OldLC_ALL ; [ "${LC_ALL+set}" ] && OldLC_ALL=$LC_ALL
LC_ALL=C ; out=${out%x};
unset LC_ALL ; [ "${OldLC_ALL+set}" ] && LC_ALL=$OldLC_ALL
printf 'Output:%10q\nExit :%2s\n' "${out}" "$?"
}
exact_output f
echo Done
ফাঁসি কার্যকর:
Output:$'\n\n\n'
Exit :25
Done
দীর্ঘ বিবরণ
পসিক্স শেলগুলি অপসারণের সাথে মোকাবেলা করার জন্য সাধারণ জ্ঞান \n
হ'ল:
একটি যোগ করুন x
s=$(printf "%s" "${1}x"); s=${s%?}
এটি আবশ্যক কারণ সর্বশেষ নতুন লাইন ( গুলি ) প্রতি পসিক্স স্পেসিফিকেশন অনুসারে কমান্ড সম্প্রসারণ দ্বারা সরানো হয়েছে :
প্রতিস্থাপনের শেষে এক বা একাধিক অক্ষরের ক্রম সরিয়ে ফেলা হচ্ছে।
একটি পিছনে সম্পর্কে x
।
এই প্রশ্নে বলা হয়েছে যে কোনও একটি x
এনকোডিংয়ে কিছু চরিত্রের পিছনের বাইট নিয়ে বিভ্রান্ত হতে পারে। তবে আমরা কীভাবে বা কোন চরিত্রটি কোনও ভাষায় কোনও সম্ভাব্য এনকোডিংয়ে আরও ভাল তা অনুমান করতে যাচ্ছি, এটি একটি কঠিন প্রস্তাব, অন্তত বলতে চাই।
যাহোক; এটি সহজভাবে ভুল ।
শুধুমাত্র নিয়ম যে আমরা অনুসরণ করতে হবে যোগ হয় ঠিক কি আমরা মুছে ফেলুন।
এটি বোঝা সহজ হওয়া উচিত যে আমরা যদি কোনও বিদ্যমান স্ট্রিংয়ে (বা বাইট ক্রম) কিছু যুক্ত করি এবং পরে আমরা ঠিক একই জিনিসটি সরিয়ে ফেলি তবে মূল স্ট্রিং (বা বাইট অনুক্রম) অবশ্যই একই হবে।
আমরা কোথায় ভুল করব? আমরা যখন অক্ষর এবং বাইটগুলি মিশ্রিত করি ।
আমরা যদি বাইট যুক্ত করি, আমাদের অবশ্যই একটি বাইট সরিয়ে ফেলতে হবে, আমরা যদি একটি অক্ষর যুক্ত করি তবে অবশ্যই আমাদের একই চরিত্রটি মুছে ফেলতে হবে ।
দ্বিতীয় বিকল্পটি, একটি অক্ষর যুক্ত করা (এবং পরে ঠিক একই চরিত্রটি মুছে ফেলা) সংশ্লেষিত এবং জটিল হয়ে উঠতে পারে এবং হ্যাঁ, কোড পৃষ্ঠা এবং এনকোডিংগুলি এগুলি পেতে পারে।
যাইহোক, প্রথম বিকল্পটি বেশ সম্ভব, এবং এটি ব্যাখ্যা করার পরে, এটি সহজ সরল হয়ে উঠবে।
আসুন একটি বাইট যুক্ত করুন, একটি এএসসিআইআই বাইট (<127), এবং জিনিসগুলি যতটা সম্ভব কম দোষযুক্ত রাখতে, আসুনের পরিসীমাতে একটি ASCII চরিত্রটি বলি। বা আমাদের যেমনটি বলা উচিত, হেক্স রেঞ্জের একটি বাইট 0x61
- 0x7a
। এর মধ্যে যে কোনও একটি বেছে নিতে দেয়, সম্ভবত একটি এক্স (সত্যই মূল্যবোধের বাইট 0x78
)। আমরা স্ট্রিংয়ের সাথে এক্সকে কনটেটেট করে এর সাথে এই বাইট যুক্ত করতে পারি (ধরে নেওয়া যাক একটি é
):
$ a=é
$ b=${a}x
যদি আমরা স্ট্রিংকে বাইটের ক্রম হিসাবে দেখি তবে আমরা দেখতে পাই:
$ printf '%s' "$b" | od -vAn -tx1c
c3 a9 78
303 251 x
একটি স্ট্রিং ক্রম যা একটি x এ শেষ হয়।
যদি আমরা সেই এক্স (বাইট মান 0x78
) সরিয়ে ফেলি তবে আমরা পাই:
$ printf '%s' "${b%x}" | od -vAn -tx1c
c3 a9
303 251
এটি কোনও সমস্যা ছাড়াই কাজ করে।
আরেকটু কঠিন উদাহরণ।
বলুন যে আমরা যে স্ট্রিংটিতে আগ্রহী সেগুলি বাইটে শেষ হয় 0xc3
:
$ a=$'\x61\x20\x74\x65\x73\x74\x20\x73\x74\x72\x69\x6e\x67\x20\xc3'
এবং মান বাইট যোগ করতে দিন 0xa9
$ b=$a$'\xa9'
স্ট্রিংটি এখন এটি হয়ে উঠেছে:
$ echo "$b"
a test string é
ঠিক আমি যা চেয়েছিলাম, শেষ দুটি বাইটগুলি ইউটিএফ 8- এর একটি চরিত্র (যাতে যে কেউ তাদের ইউটিএফ 8 কনসোলে এই ফলাফলগুলি পুনরুত্পাদন করতে পারে)।
আমরা যদি একটি অক্ষর অপসারণ করি তবে মূল স্ট্রিংটি পরিবর্তন করা হবে। তবে এটি যা আমরা যুক্ত করেছি তা নয়, আমরা একটি বাইট মান যুক্ত করেছি, যা এক্স হিসাবে লেখা হয়, তবে যাইহোক একটি বাইট।
বাইটদের চরিত্র হিসাবে ভুল ব্যাখ্যা করা এড়াতে আমাদের কী প্রয়োজন। আমাদের যা প্রয়োজন তা হ'ল একটি ক্রিয়া যা আমরা ব্যবহার করা বাইট সরিয়ে ফেলি 0xa9
। প্রকৃতপক্ষে, ছাই, বাশ, লক্ষ এবং ম্যাক্স সকলেই ঠিক এমনটি করে বলে মনে হচ্ছে:
$ c=$'\xa9'
$ echo ${b%$c} | od -vAn -tx1c
61 20 74 65 73 74 20 73 74 72 69 6e 67 20 c3 0a
a t e s t s t r i n g 303 \n
তবে ksh বা zsh নয়।
তবে এটি সমাধান করা খুব সহজ, সেই সমস্ত শেলকে বাইট অপসারণ করতে বলুন :
$ LC_ALL=C; echo ${b%$c} | od -vAn -tx1c
এটিই, সমস্ত শেলগুলি পরীক্ষার কাজ (যশ ব্যতীত) (স্ট্রিংয়ের শেষ অংশের জন্য):
ash : s t r i n g 303 \n
dash : s t r i n g 303 \n
zsh/sh : s t r i n g 303 \n
b203sh : s t r i n g 303 \n
b204sh : s t r i n g 303 \n
b205sh : s t r i n g 303 \n
b30sh : s t r i n g 303 \n
b32sh : s t r i n g 303 \n
b41sh : s t r i n g 303 \n
b42sh : s t r i n g 303 \n
b43sh : s t r i n g 303 \n
b44sh : s t r i n g 303 \n
lksh : s t r i n g 303 \n
mksh : s t r i n g 303 \n
ksh93 : s t r i n g 303 \n
attsh : s t r i n g 303 \n
zsh/ksh : s t r i n g 303 \n
zsh : s t r i n g 303 \n
কেবল সহজ, শেলটিকে একটি এলসি_এলএল = সি অক্ষর অপসারণ করতে বলুন, যা থেকে সমস্ত বাইট মানের জন্য এক বাইট 0x00
হয় 0xff
।
মন্তব্যের সমাধান:
মন্তব্যে আলোচিত উদাহরণের জন্য, একটি সম্ভাব্য সমাধান (যা zsh এ ব্যর্থ হয়) হ'ল:
#!/bin/bash
LC_ALL=zh_HK.big5hkscs
a=$(printf '\210\170');
b=$(printf '\170');
unset OldLC_ALL ; [ "${LC_ALL+set}" ] && OldLC_ALL=$LC_ALL
LC_ALL=C ; a=${a%"$b"};
unset LC_ALL ; [ "${OldLC_ALL+set}" ] && LC_ALL=$OldLC_ALL
printf '%s' "$a" | od -vAn -c
এটি এনকোডিংয়ের সমস্যাটি দূর করবে।
$IFS
, তাই এটি যুক্তি হিসাবে ধরা হবে না।