मैं बिना किसी रूपांतरण के बाइट्स वर्बेटिम की नकल करने के लिए बैश में बाइनरी के साथ कैसे काम कर सकता हूं?


14

मैं महत्वाकांक्षी रूप से एक सी + + कोड का अनुवाद करने की कोशिश कर रहा हूं, जो कई कारणों से है।

यह कोड मेरे उप-क्षेत्र के लिए विशिष्ट फ़ाइल प्रकार को पढ़ता है और उसमें हेरफेर करता है जो बाइनरी में पूरी तरह से लिखा और संरचित है। मेरा पहला बाइनरी से संबंधित कार्य हेडर के पहले 988 बाइट्स की नकल करना है, बिल्कुल-जैसा है, और उन्हें एक आउटपुट फाइल में डाल दिया है कि मैं लेखन को जारी रख सकता हूं क्योंकि मैं बाकी जानकारी उत्पन्न करता हूं।

मुझे पूरा यकीन है कि मेरा वर्तमान समाधान काम नहीं कर रहा है, और वास्तविक रूप से मैंने इसे निर्धारित करने का एक अच्छा तरीका नहीं निकाला है। इसलिए भले ही यह वास्तव में सही ढंग से लिखा गया हो, फिर भी मुझे यह जानने की ज़रूरत है कि मैं यह कैसे सुनिश्चित करूँगा!

यह मैं अभी कर रहा हूँ:

hdr_988=`head -c 988 ${inputFile}`
echo -n "${hdr_988}" > ${output_hdr}
headInput=`head -c 988 ${inputTrack} | hexdump`
headOutput=`head -c 988 ${output_hdr} | hexdump`
if [ "${headInput}" != "${headOutput}" ]; then echo "output header was not written properly.  exiting.  please troubleshoot."; exit 1; fi

अगर मैं फ़ाइल के इस हिस्से की जांच करने के लिए हेक्सडंप / xxd का उपयोग करता हूं, हालांकि मैं इसे ज्यादातर नहीं पढ़ सकता हूं, तो कुछ गलत लगता है। और जो कोड मैंने तुलना के लिए लिखा है वह केवल मुझे बताता है कि क्या दो तार समान हैं, न कि अगर वे जिस तरह से मुझे चाहते हैं, उनकी नकल की जाती है।

क्या बैश में ऐसा करने का एक बेहतर तरीका है? क्या मैं फ़ाइल बाइनरी कॉपी करने के लिए मूल बाइनरी में बाइनरी बाइट्स को कॉपी / रीड कर सकता हूं? (और आदर्श रूप में अच्छी तरह से चर के रूप में स्टोर करने के लिए)।


आप उपयोग कर सकते हैं ddअलग-अलग बाइट (अपनी स्थापना के कॉपी करने के लिए countकरने के लिए 1)। मैं उन्हें संग्रहीत करने के बारे में निश्चित नहीं हूँ, हालाँकि।
DDPWNAGE

सी तरीके से बकवास मत करो, यह कई सिरदर्द पैदा करेगा। इसके बजाय उचित बैश निर्माणों का उपयोग करें
Ferrybig

जवाबों:


22

शेल स्क्रिप्ट में निम्न स्तर पर बाइनरी डेटा से निपटना आम तौर पर एक बुरा विचार है।

bashवेरिएबल्स में बाइट नहीं हो सकती है 0. zshएकमात्र शेल है जो उस बाइट को अपने वेरिएबल्स में स्टोर कर सकता है।

किसी भी स्थिति में, कमांड तर्क और पर्यावरण चर उन बाइट्स को शामिल नहीं कर सकते हैं क्योंकि वे execveसिस्टम कॉल में एनयूएल सीमांकित तार हैं।

यह भी ध्यान दें:

var=`cmd`

या इसका आधुनिक रूप:

var=$(cmd)

के उत्पादन से सभी अनुगामी newline वर्ण स्ट्रिप्स cmd। इसलिए, यदि बाइनरी आउटपुट 0xa बाइट्स में समाप्त हो जाता है, तो इसे स्टोर किए जाने पर मंगवाया जाएगा $var

यहां, आपको उदाहरण के लिए, एन्कोडेड डेटा संग्रहीत करना होगा xxd -p

hdr_988=$(head -c 988 < "$inputFile" | xxd -p)
printf '%s\n' "$hdr_988" | xxd -p -r > "$output_hdr"

आप सहायक कार्यों को परिभाषित कर सकते हैं जैसे:

encode() {
  eval "$1"='$(
    shift
    "$@" | xxd -p  -c 0x7fffffff
    exit "${PIPESTATUS[0]}")'
}

decode() {
  printf %s "$1" | xxd -p -r
}

encode var cat /bin/ls &&
  decode "$var" | cmp - /bin/ls && echo OK

xxd -pआउटपुट स्पेस कुशल नहीं है क्योंकि यह 2 बाइट्स में 1 बाइट को एनकोड करता है, लेकिन इसके साथ जोड़तोड़ करना आसान बनाता है (कंक्रीटिंग, पार्ट्स निकालना)। base64एक है जो 4 में 3 बाइट्स को एनकोड करता है, लेकिन इसके साथ काम करना उतना आसान नहीं है।

ksh93खोल अंतर्निहित एन्कोडिंग प्रारूप (का उपयोग करता है base64), जो आप अपने साथ उपयोग कर सकते हैं readऔर printf/ printउपयोगिताओं:

typeset -b var # marked as "binary"/"base64-encoded"
IFS= read -rn 988 var < input
printf %B var > output

अब, यदि शेल या एनवी चर, या कमांड तर्कों के माध्यम से कोई पारगमन नहीं है, तो आपको ठीक होना चाहिए जब तक कि आपके द्वारा उपयोग की जाने वाली उपयोगिताओं किसी भी बाइट मान को संभाल सकती हैं। लेकिन ध्यान दें कि पाठ उपयोगिताओं के लिए, अधिकांश गैर-जीएनयू कार्यान्वयन एनयूएल बाइट्स को संभाल नहीं सकते हैं, और आप मल्टी-बाइट पात्रों के साथ समस्याओं से बचने के लिए लोकेल को सी को ठीक करना चाहेंगे। अंतिम वर्ण नई पंक्ति वर्ण नहीं होने के कारण समस्याएँ भी पैदा कर सकता है और साथ ही बहुत लंबी लाइनें (दो 0xa बाइट्स के बीच बाइट्स का अनुक्रम जो लंबे समय तक होता है LINE_MAX)।

head -cजहां यह उपलब्ध है वह यहां ठीक होना चाहिए, क्योंकि यह बाइट्स के साथ काम करने के लिए है, और डेटा को पाठ के रूप में व्यवहार करने का कोई कारण नहीं है। इसलिए

head -c 988 < input > output

ठीक हो जाना चाहिए। कम से कम जीएनयू, फ्रीबीएसडी और ksh93 बिलिन कार्यान्वयन व्यवहार में ठीक हैं। POSIX -cविकल्प निर्दिष्ट नहीं करता है , लेकिन कहते हैं कि headकिसी भी लंबाई की लाइनों का समर्थन करना चाहिए (सीमित नहीं LINE_MAX)

के साथ zsh:

IFS= read -rk988 -u0 var < input &&
print -rn -- $var > output

या:

var=$(head -c 988 < input && echo .) && var=${var%.}
print -rn -- $var > output

यहां तक ​​कि zshअगर $varNUL बाइट्स होते हैं , तो आप इसे zshबिल्डिंस (जैसे printऊपर) या फ़ंक्शंस में तर्क के रूप में पास कर सकते हैं , लेकिन निष्पादन योग्य के लिए तर्कों के रूप में नहीं, जैसा कि एक्ज़िक्युटेबल्स को दिए गए तर्क एनयूएल सीमांकित स्ट्रिंग्स हैं, यह एक कर्नेल सीमा है, शेल से स्वतंत्र है।


zshएकमात्र शेल नहीं है जो शेल चर में एक या एक से अधिक एनयूएल बाइट्स को स्टोर कर सकता है। ksh93ऐसा भी कर सकते हैं। आंतरिक रूप से, ksh93बस द्विआधारी चर को बेस 64-एन्कोडेड स्ट्रिंग के रूप में संग्रहीत करता है।
fpmurphy

@ fpmurphy1, यह वह नहीं है जिसे मैं बाइनरी डेटा से निपटने के लिए कहता हूं , वैरिएबल में बाइनरी डेटा नहीं है, इसलिए आप उदाहरण के लिए उन पर किसी भी शेल ऑपरेटर का उपयोग नहीं कर सकते हैं, आप उन्हें बिलिंस या फ़ंक्शंस में नहीं भेज सकते डिकोड किया गया फ़ॉर्म ... मैं इसे बेसिन6464 एन्कोडिंग / डिकोडिंग समर्थन के बजाय कॉल करूंगा ।
स्टीफन चेज़लस

11

मैं महत्वाकांक्षी रूप से एक सी + + कोड का अनुवाद करने की कोशिश कर रहा हूं, जो कई कारणों से है।

सही है। लेकिन शायद आपको इसे न करने के लिए एक बहुत ही महत्वपूर्ण कारण पर विचार करना चाहिए। असल में, "बैश" / "श" / "csh" / "ksh" और जैसे बाइनरी डेटा को संसाधित करने के लिए डिज़ाइन नहीं किए गए हैं, और न ही अधिकांश मानक UNIX / LINUX उपयोगिताओं के हैं।

आप सी ++ के साथ चिपके रहना या पाइथन, रूबी या पर्ल जैसी स्क्रिप्टिंग भाषा का उपयोग करना बेहतर होगा, जो बाइनरी डेटा से निपटने में सक्षम है।

क्या बैश में ऐसा करने का एक बेहतर तरीका है?

बेहतर तरीका यह है कि इसे बाश में न करें।


4
+1 के लिए "बेहतर तरीका यह है कि इसे बाश में न करें।"
गुंतराम ब्लोहम

1
इस मार्ग पर नहीं जाने का एक और कारण यह है कि परिणामी आवेदन काफी धीमा हो जाएगा और अधिक सिस्टम संसाधनों का उपभोग करेगा।
fpmurphy

बैश पाइपलाइन उच्च स्तरीय डोमेन विशिष्ट प्रकार की भाषा के रूप में कार्य कर सकती है जो समझ को बढ़ा सकती है। एक पाइप लाइन है कि द्विआधारी नहीं है के बारे में कुछ भी नहीं है, और वहाँ कमांड लाइन उपकरण के रूप में लागू विभिन्न उपयोगिताओं हैं कि बाइनरी डेटा के साथ सहभागिता ( ffmpeg, imagemagick, dd)। अब अगर कोई चीजों को एक साथ मिलाने के बजाय प्रोग्रामिंग कर रहा है तो एक पूर्ण संचालित प्रोग्रामिंग भाषा का उपयोग करने का तरीका है।
आरएच

6

आपके प्रश्न से:

हेडर की पहली 988 लाइनों की प्रतिलिपि बनाएँ

यदि आप 988 लाइनों की नकल कर रहे हैं, तो यह एक पाठ फ़ाइल की तरह लगता है, बाइनरी नहीं। हालाँकि, आपका कोड 988 बाइट मान रहा है, न कि 988 लाइनें, इसलिए मैं मान लूंगा कि बाइट्स सही है।

hdr_988=`head -c 988 ${inputFile}`
echo -n "${hdr_988}" > ${output_hdr}

यह हिस्सा काम नहीं कर सकता है। एक बात के लिए, स्ट्रीम में कोई भी NUL बाइट्स छीन जाएगा, क्योंकि आप ${hdr_988}कमांड लाइन तर्क के रूप में उपयोग करते हैं , और कमांड लाइन तर्क में NUL नहीं हो सकता है। हो सकता है कि बैकटिक्स व्हॉट्सएप मुंगिंग कर रहा हो (मुझे इस बारे में यकीन नहीं है)। (वास्तव में, चूंकि echoएक अंतर्निहित है, एनयूएल प्रतिबंध लागू नहीं हो सकता है , लेकिन मैं कहूंगा कि यह अभी भी iffy है।)

सिर्फ शेल फ़ाइल के माध्यम से पारित किए बिना, हेडर को सीधे इनपुट फाइल से आउटपुट फाइल तक क्यों नहीं लिखा जाता है?

head -c 988 "${inputFile}" >"${output_hdr}"

या, और अधिक,

dd if="${inputFile}" of="${output_hdr}" bs=988 count=1

चूंकि आप उल्लेख करते हैं कि आप bashPOSIX शेल का उपयोग कर रहे हैं , आपके पास प्रक्रिया प्रतिस्थापन उपलब्ध है, इसलिए परीक्षण के रूप में इसके बारे में क्या है?

cmp <(head -c 988 "${inputFile}") <(head -c 988 "${output_hdr}")

अंत में: बैकटिक्स के बजाय उपयोग करने पर विचार करें $( ... )


ध्यान दें कि गैर-नियमित फ़ाइलों के लिए ddआवश्यक नहीं है head। उन 988 बाइट्स को प्राप्त करने के लिए जितनी आवश्यक हो headउतने read(2)सिस्टम कॉल करेंगे जबकि ddसिर्फ एक ही करेगा read(2)। GNU ddमें iflag=fullblockउस ब्लॉक को पूरी तरह से पढ़ने और पढ़ने की कोशिश है, लेकिन यह तब की तुलना में कम पोर्टेबल है head -c
स्टीफन चेजलस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.