नए प्रश्न के लिए, यह स्क्रिप्ट काम करती है:
#!/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
लंबा विवरण
POSIX गोले को हटाने से निपटने के लिए सामान्य ज्ञान \n
है:
जोड़ें x
s=$(printf "%s" "${1}x"); s=${s%?}
इसकी आवश्यकता है क्योंकि पिछले नई लाइन ( एस ) को POSIX विनिर्देश प्रति कमांड विस्तार द्वारा हटा दिया गया है :
प्रतिस्थापन के अंत में एक या अधिक वर्णों के अनुक्रमों को हटाना।
एक अनुगामी के बारे में x
।
इस प्रश्न में कहा गया है कि x
कुछ एन्कोडिंग में कुछ चरित्र के अनुगामी बाइट के साथ भ्रमित किया जा सकता है। लेकिन हम यह अनुमान लगाने जा रहे हैं कि कुछ संभावित एन्कोडिंग में किसी भाषा में कौन सा या कौन सा चरित्र बेहतर है, जो कि कम से कम कहने के लिए एक कठिन प्रस्ताव है।
हालाँकि; वह बस गलत है ।
एकमात्र नियम जिसे हमें अनुसरण करने की आवश्यकता है वह है ठीक उसी तरह जो हम हटाते हैं।
यह समझना आसान होना चाहिए कि यदि हम किसी मौजूदा स्ट्रिंग (या बाइट अनुक्रम) में कुछ जोड़ते हैं और बाद में हम उसी चीज़ को बिल्कुल हटा देते हैं, तो मूल स्ट्रिंग (या बाइट अनुक्रम) समान होना चाहिए।
हम कहां गलत हैं? जब हम पात्रों और बाइट्स को मिलाते हैं ।
यदि हम एक बाइट जोड़ते हैं, तो हमें एक बाइट को हटाना होगा, यदि हम एक चरित्र को जोड़ते हैं तो हमें ठीक उसी वर्ण को निकालना होगा ।
दूसरा विकल्प, एक चरित्र को जोड़ना (और बाद में सटीक समान चरित्र को हटाने) जटिल और जटिल हो सकता है, और, हाँ, कोड पृष्ठ और एन्कोडिंग रास्ते में मिल सकते हैं।
हालांकि, पहला विकल्प काफी संभव है, और, यह समझाने के बाद, यह सरल सरल हो जाएगा।
आइए एक बाइट, एक ASCII बाइट (<127) को जोड़ते हैं, और चीजों को जितना संभव हो उतना कम दोषपूर्ण रखने के लिए, आइए az की श्रेणी में एक 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 é
वास्तव में मैं जो चाहता था, अंतिम दो बाइट्स utf8 में एक चरित्र हैं (इसलिए कोई भी अपने utf8 कंसोल में इस परिणाम को पुन: पेश कर सकता है)।
यदि हम एक चरित्र को हटाते हैं, तो मूल स्ट्रिंग को बदल दिया जाएगा। लेकिन यह वह नहीं है जो हमने जोड़ा था, हमने एक बाइट मान जोड़ा, जो कि एक एक्स के रूप में लिखा जाना होता है, लेकिन वैसे भी एक बाइट।
पात्रों के रूप में गलत बाइट से बचने के लिए हमें क्या करने की आवश्यकता है। हमें जो कुछ चाहिए वह एक ऐसी क्रिया है जो हमारे द्वारा उपयोग की जाने वाली बाइट को हटा देती है 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
बस इतना आसान है, एक LC_ALL = C वर्ण को हटाने के लिए शेल को बताएं, जो कि सभी बाइट मानों के लिए बिल्कुल एक बाइट 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
, इसलिए इसे एक तर्क के रूप में कैप्चर नहीं किया जाएगा।