खोजो | xargs shasum चेकसम फ़ाइल (समय से पहले) का चेकसम बनाता है और चेक करते समय विफल हो जाता है


10

मेरी समस्या (एक स्क्रिप्ट में #!/bin/sh) निम्नानुसार है: मैं अभिलेखीय उद्देश्यों के लिए एक निर्देशिका में सभी फ़ाइलों को चेकसम करने का प्रयास करता हूं। सभी फ़ाइल नाम के साथ चेकसम (मेरे मामले में sha1) फ़ाइल को एक ही निर्देशिका में रहना चाहिए। कहते हैं कि हमारे पास ~/testफ़ाइलों f1और f2: के साथ एक निर्देशिका है ।

mkdir ~/test
cd ~/test
echo "hello" > f1
echo "world" > f2

अब के साथ जाँच की गणना

find -maxdepth 1 -type f -printf '%P\n' | xargs shasum

जैसा मैं चाहता हूं वैसा ही करता है, यह केवल वर्तमान निर्देशिका की सभी फाइलों को सूचीबद्ध करता है और sha1 sums की गणना करता है (अधिकतम सीमा को बदला जा सकता है)। STDOUT पर आउटपुट है:

f572d396fae9206628714fb2ce00f72e94f2258f  f1
9591818c07e900db7e1e0bc4b884c945e6a61b24  f2

दुर्भाग्य से, जब एक फ़ाइल के साथ इसे बचाने की कोशिश की जा रही है

find -maxdepth 1 -type f -printf '%P\n' | xargs shasum > sums.sha1

परिणामी फ़ाइल अपने लिए चेकसम प्रदर्शित करती है:

da39a3ee5e6b4b0d3255bfef95601890afd80709  sums.sha1
f572d396fae9206628714fb2ce00f72e94f2258f  f1
9591818c07e900db7e1e0bc4b884c945e6a61b24  f2  

और इसलिए बाद में विफल रहता है shasum --check, क्योंकि अंतिम राशि की बचत के दौरान अतिरिक्त फ़ाइल संशोधन की स्पष्ट समस्या है।

मैंने चारों ओर देखा और इसके -pलिए ध्वज का उपयोग करके xargs, मुझे पता चला कि यह किसी भी तरह से कमांड फाइल को निष्पादित करने से पहले आउटपुट फ़ाइल बनाता है, इसलिए अतिरिक्त फ़ाइल मिली है और चेकसम की जाएगी ...

मुझे पता है कि वर्कअराउंड के रूप में मैं चेकसम को किसी अन्य स्थान (टेम्प डायरेक्टरी के माध्यम से mktemp) को बचा सकता था या विशेष रूप से ढूंढने में इसे बाहर कर सकता था, लेकिन मैं यह समझना चाहता हूं कि यह ऐसा क्यों करता है - जो मेरी नजर में उपयोगी नहीं है। उदाहरण के लिए यदि पहला कमांड यह जाँच करेगा कि आउटपुट फाइल पहले से डिस्क पर है, तो उसे कभी सही उत्तर नहीं मिलेगा ...


8
ऐसा नहीं है xargs, यह खोल ही है कि इस फ़ाइल बनाता है, क्योंकि है से पहले किसी भी कमांड सबसे पहले खोल रीडायरेक्ट सभी इनपुट, आउटपुट और पाइप निष्पादित किया जाता है, ताकि जब findआउटपुट फ़ाइल शुरू होता है पहले से मौजूद है। -execइसके स्थान पर प्रयोग करें :find -maxdepth 1 -type f -exec sh -c 'shasum "$@" > sums.sha1' {} +
जिमीज

@ जिमीज, यह shआवश्यक नहीं है कि काम करने के लिए या तो कई चालान आवश्यक हैं। ध्यान दें कि आपको $0पहले के लिए एक तर्क की आवश्यकता है {}
स्टीफन चेज़लस

@ जिमीज आपका अन्य उत्तर जो सुझाया गया है teeवह गायब हो गया है? मैंने कोशिश की और यह ठीक काम करता है, मैंने भी जोड़ने के साथ STDOUT को दबा दिया 1>/dev/null। क्या उत्तर में कुछ गड़बड़ था या यह एक बग था?
user121391

@ user121391 स्टीफन ने बताया कि कभी-कभी दौड़ की स्थिति समस्या हो सकती है, जो सच लगती है। मैंने इसे थोड़ी देर के लिए हटा दिया ताकि आप देख सकें, लेकिन अगर आपके पास इस सूची की कई फाइलें हैं जो कमांड गलत हो सकती हैं।
जिमीज

@ जिमीज आह, मैं देख रहा हूं। यह उपयोगी हो सकता है यदि आप इसे मुद्दों के बारे में चेतावनी के साथ उपसर्ग करते हैं, क्योंकि मुझे लगता है कि यह इतनी अच्छी तरह से ज्ञात नहीं है कि यह हो सकता है। अन्यथा, मैं उन मामलों के लिए आपके उत्तर को स्वीकार कर लेता यदि आवर्ती रन में पुरानी फ़ाइल और एंथन के मामले शामिल हैं, जहां इसे फिर से लिखा जाना चाहिए।
user121391

जवाबों:


12

आप फ़ाइल को xargsउपयोग करने से रोक सकते हैं :

find . -maxdepth 1 -type f ! -name sums.sha1 -printf '%P\n' |
  xargs -r shasum -- > sums.sha1

फ़ाइल नाम के साथ समस्याओं को रोकने के लिए जिनके पास रिक्तियां या नईलाइनें या उद्धरण या बैकस्लैश हैं, मैं फिर भी उपयोग करूंगा:

find . -maxdepth 1 -type f ! -name sums.sha1 -printf '%P\0' |
  xargs -r0 shasum -- > sums.sha1

बजाय।

--फ़ाइल नाम है कि के साथ शुरू के साथ समस्याओं से बचने के लिए है -। हालाँकि यह नामक फ़ाइल के लिए मदद नहीं करेगा -। अगर आपने -print0इसके बजाय उपयोग किया -printf '%P\0'होता, तो आपको इसकी आवश्यकता नहीं होती --और -फ़ाइल के साथ कोई समस्या नहीं होती ।


आपका समाधान वह है जो मैंने प्रयोग करके समाप्त किया। मुझे विशेष रूप से पसंद है कि बाद के रन चेकसम फाइल को रिहैश नहीं करते हैं और डायरेक्टरी को फुलाते हैं। इसके अलावा, मेरी स्क्रिप्ट में मुझे basenameदिए गए पूर्ण पथ से sums.sha1 फ़ाइल नाम मिला (यह प्रश्न में शामिल नहीं था, लेकिन यह दूसरों की मदद कर सकता है)।
user121391

7

जब से आप उपयोग कर रहे हैं -maxdepth 1, मुझे लगता है कि आप पुनरावृत्ति नहीं चाहते हैं। यदि हां, तो इसके बजाय इसे शेल में करें:

for f in ~/test/*; do
    shasum -- "$f"
done > sums.sha1

निर्देशिकाओं को छोड़ने के लिए, आप यह कर सकते हैं:

for f in ~/test/*; do
    [ ! -d "$f" ] && shasum -- "$f"
done > sums.sha1

यदि आपको पुनरावृत्ति की आवश्यकता है और उपयोग कर रहे हैं bash, तो:

shopt -s globstar
for f in ~/test/**; do
    [ ! -d "$f" ] && shasum -- "$f"
done > sums.sha1

ध्यान दें कि इन सभी दृष्टिकोणों में रिक्त स्थान के नामों पर काम करने का लाभ है, जिसमें रिक्त स्थान, नई सूची या कुछ भी शामिल हैं।


मुझे लगता है कि आप यह उल्लेख करेंगे कि यह ओपी किसी भी मुद्दे को हल करेगा, जिसमें उनके साथ ही नए नाम के साथ फाइल नाम होंगे। दूसरी तरफ अगर sums.sha1पहले से ही है (पिछले रन से) तो आपका समाधान इसमें शामिल होगा।
एंथन

क्षमा करें, मैंने पहले स्पष्ट नहीं किया था: मैक्सडेप केवल इस उदाहरण में उपयोग किया गया था, मैं एक फ़ंक्शन का उपयोग करता हूं जहां उपयोगकर्ता / स्क्रिप्ट किसी भी मूल्य की आपूर्ति कर सकता है, हालांकि वर्तमान में मुझे केवल 1. गहराई चाहिए
user121391

@ user121391 एक पुनरावर्ती दृष्टिकोण के लिए अद्यतन जवाब देखें।
terdon

ध्यान दें कि यह अन्य प्रकार की गैर-नियमित फ़ाइलों जैसे कि पाइप, डिवाइस ... (और उनसे सहानुभूति) को चेकसम करने का भी प्रयास करेगा।
स्टीफन चेज़लस

धन्यवाद, व्यक्तिगत रूप से मैं उपयोग कर रहा हूं sh, लेकिन आपका जवाब दूसरों की मदद कर सकता है।
user121391

4

साथ zsh:

shasum -- *(D.) > sums.sha1

पुनर्निर्देशन से पहले ग्लोब का विस्तार किया जाएगा, इसलिए sums.sha1यह शामिल नहीं होगा यदि यह पहले स्थान पर नहीं था।

Dके रूप में डॉट-फ़ाइलें (छिपी हुई फ़ाइलें) को शामिल findकरना होगा। .केवल नियमित फ़ाइलों का चयन करना है (जैसे आपके -type f)।

sums.sha1वैसे भी पहले स्थान पर होने के कारण इसे बाहर करने के लिए :

setopt extendedglob # best in ~/.zshrc
shasum -- ^sums.sha1(D.) > sums.sha1

ध्यान दें कि जो एक shasum कमांड चलाते हैं , इसलिए यदि सूची बहुत बड़ी है तो आप "Arg list बहुत लंबी" त्रुटि देखकर समाप्त हो सकते हैं। उस के आसपास काम करने के लिए:

autoload zargs
zargs -e/ -- *(D.) / shasum > sums.sha1

मैं एक फ़ाइल नामक संभावित समस्याओं से बचने के ./*बजाय उपयोग करने की सलाह *दूंगा -


मैंने प्रश्न को शेल के प्रकार के साथ संपादित किया, लेकिन आपका उत्तर मुझे याद दिलाता है कि मैं कुछ समय पहले zsh पर स्विच करना चाहता था ...;)
user121391

1

जैसा कि अन्य उत्तरों में पहले ही कहा जा चुका है कि sums.sha1आपकी पाइपलाइन को निष्पादित करने से पहले शेल खोल देता है और फ़ाइल बनाता है । आप उस प्रोग्राम का उपयोग कर सकते हैं spongeजो moreutilsकई वितरण के पैकेज का हिस्सा है । शेल के विपरीत पुनर्निर्देशन spongeतब तक इंतजार करेगा जब तक कि वह सब कुछ प्राप्त न कर ले, फाइल खोलने से पहले। आम तौर पर इसका उपयोग तब किया जाता है जब आप उसी पाइपलाइन में पढ़ी गई फ़ाइल लिखना चाहते हैं।

आपके मामले में इसका उपयोग इस तरह किया जाता है:

$ find -maxdepth 1 -type f -printf '%P\n' |xargs shasum |sponge sums.sha1
$ cat sums.sha1
31836aeaab22dc49555a97edb4c753881432e01d  B
7d157d7c000ae27db146575c08ce30df893d3a64  A

0

खोज / xargs आदि के विकल्प के रूप में आप sha1deep चाहते हैं। यह शायद एक अलग पैकेज में है - हालांकि मेरे बॉक्स में यह md5deep पैकेज में आता है।

जैसा कि दूसरों ने कहा है कि sums.sha1 खोज शुरू होने से पहले ही शेल द्वारा बनाया गया है। के साथ एक चाल ! -name sums.sha1के लिए findइच्छा के रूप में, काम करेंगे

find -maxdepth 1 -type f -printf '%P\n' | xargs shasum | grep -v ' sums\.sha1$' > sums.sha1
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.