पूर्ण फाइलसिस्टम पर इन-प्लेस लाइन विलोपन?


11

अनुप्रयोग बग के रूप में अभी तक अनजाने में होने के कारण, मेरे पास एक पूर्ण डिस्क के साथ कई सौ सर्वर हैं। एक फ़ाइल है जो डुप्लिकेट लाइनों से भरी गई है - लॉग फ़ाइल नहीं है, लेकिन एक उपयोगकर्ता पर्यावरण फ़ाइल चर परिभाषाओं के साथ है (इसलिए मैं बस फ़ाइल को हटा नहीं सकता)।

मैंने sedत्रुटिपूर्ण रूप से जोड़ी गई लाइनों की जांच करने और उन्हें हटाने के लिए एक साधारण कमांड लिखा , और इसे फ़ाइल की एक स्थानीय प्रतिलिपि पर परीक्षण किया। यह इरादा के अनुसार काम किया।

हालाँकि, जब मैंने इसे पूरी डिस्क के साथ सर्वर पर आज़माया, तो मुझे लगभग निम्न त्रुटि हुई (यह मेमोरी से है, कॉपी और पेस्ट से नहीं):

sed: couldn't flush /path/to/file/sed8923ABC: No space left on deviceServerHostname

बेशक, मुझे पता है कि कोई जगह नहीं बची है। इसलिए मैं सामान हटाने की कोशिश कर रहा हूं! ( sedमैं जिस कमांड का उपयोग कर रहा हूं, वह 4000+ लाइन फ़ाइल को लगभग 90 लाइनों तक कम कर देगा।)

मेरी sedआज्ञा सिर्फ हैsed -i '/myregex/d' /path/to/file/filename

क्या कोई तरीका है जो मैं इस कमांड को पूर्ण डिस्क के बावजूद लागू कर सकता हूं?

(यह स्वचालित होना चाहिए, क्योंकि मुझे इसे त्वरित-फिक्स के रूप में कई सौ सर्वरों पर लागू करने की आवश्यकता है।)

(स्पष्ट रूप से एप्लिकेशन बग का निदान करने की आवश्यकता है, लेकिन इस बीच सर्वर सही तरीके से काम नहीं कर रहे हैं ...)


अद्यतन: मैंने जिस स्थिति का सामना किया था उसे कुछ और हटाकर हल किया गया था जो मुझे पता चला कि मैं हटा सकता हूं, लेकिन मैं अभी भी इस प्रश्न का उत्तर चाहूंगा, जो भविष्य में और अन्य लोगों के लिए उपयोगी होगा।

/tmpएक नहीं है; यह एक ही फाइल सिस्टम पर है।

इससे पहले कि मैं डिस्क स्थान को मुक्त करता, मैंने परीक्षण किया और पता लगाया कि मैं viफ़ाइल को खोलकर और चलाकर लाइनों को हटा सकता हूं :g/myregex/dऔर फिर सफलतापूर्वक परिवर्तनों को सहेज सकता हूं :wq। ऐसा लगता है कि एक अस्थायी फ़ाइल रखने के लिए एक अलग फाइल सिस्टम का सहारा लिए बिना, इसे स्वचालित करना संभव है .... (?)?



1
sed -iपर संचालित करने के लिए एक अस्थायी प्रतिलिपि बनाता है। मुझे संदेह है कि यह edइसके लिए बेहतर होगा, हालांकि मैं एक वास्तविक समाधान के खिलाफ मुकदमा चलाने के लिए पर्याप्त परिचित नहीं हूं
एरिक रेनॉफ

2
साथ edआप चलाना चाहते हैं: printf %s\\n g/myregex/d w q | ed -s infileलेकिन ध्यान रखें कुछ कार्यान्वयन भी अस्थायी फ़ाइलों का उपयोग जैसे sed(आप की कोशिश कर सकते बिजीबॉक्स एड - afaik कि यह एक अस्थायी फ़ाइल बनाने नहीं करता है)
don_crissti

1
@Wildcard - मज़बूती से w / नहीं echo। उपयोग करें printf। और sedअंतिम पंक्ति में कुछ चार आप जोड़ सकते हैं ताकि आप खाली स्थान खोने से बच सकें। इसके अलावा, आपके शेल को एक कमांड-लाइन में पूरी फाइल को संभालने में सक्षम होना चाहिए। यह आपका जोखिम है - पहले परीक्षण करें। bashउस पर विशेष रूप से बुरा है (मुझे लगता है कि यह w / स्टैक स्पेस करना है?) और कभी भी आप पर बीमार पड़ सकता है। दो sed'si कम से कम उन दोनों के बीच अच्छे प्रभाव के लिए कर्नेल के पाइप बफर का प्रयोग करेंगे की सिफारिश की है, लेकिन विधि काफी समान है। आपकी कमांड सब चीज़ भी अलग हो जाएगी fileकि sed w / सफल है या नहीं।
mikeserv

1
@Wildcard - कोशिश करो sed '/regex/!H;$!d;x' <file|{ read v && cat >file;}और अगर यह काम करता है मेरे बाकी जवाब पढ़ें। '
मोकेसर

जवाबों:


10

-iविकल्प वास्तव में मूल फ़ाइल अधिलेखित नहीं करता है। यह आउटपुट के साथ एक नई फ़ाइल बनाता है, फिर इसे मूल फ़ाइल नाम में बदल देता है। चूँकि आपके पास इस नई फ़ाइल के लिए फाइल सिस्टम पर जगह नहीं है, यह विफल है।

आपको अपनी स्क्रिप्ट में स्वयं ऐसा करने की आवश्यकता होगी, लेकिन एक अलग फाइल सिस्टम पर नई फ़ाइल बनाएं।

इसके अलावा, यदि आप एक regexp से मेल खाने वाली लाइनों को हटा रहे हैं, तो आप इसके grepबजाय उपयोग कर सकते हैं sed

grep -v 'myregex' /path/to/filename > /tmp/filename && mv /tmp/filename /path/to/filename

सामान्य तौर पर, प्रोग्राम के लिए इनपुट और आउटपुट के समान फ़ाइल का उपयोग करना संभव नहीं है - जैसे ही यह फ़ाइल पर लिखना शुरू करता है, प्रोग्राम का वह हिस्सा जो फ़ाइल से पढ़ रहा है, वह अब मूल सामग्री नहीं देखेगा। इसलिए इसे या तो मूल फ़ाइल को पहले कहीं कॉपी करना है, या एक नई फ़ाइल लिखना है और जब यह किया जाता है तो इसे नाम बदलें।

यदि आप एक अस्थायी फ़ाइल का उपयोग नहीं करना चाहते हैं, तो आप फ़ाइल सामग्री को स्मृति में कैशिंग करने का प्रयास कर सकते हैं:

file=$(< /path/to/filename)
echo "$file" | grep -v 'myregex' > /path/to/filename

1
क्या यह अनुमति, स्वामित्व और टाइमस्टैम्प को संरक्षित करता है? हो सकता है rsync -a --no-owner --no-group --remove-source-files "$backupfile" "$destination"कि यहाँ से
हस्त्तूर

@ हस्तूर - क्या आपका मतलब यह है कि sed -iउस सामान को संरक्षित करना है?
mikeserv

2
@ हस्तूर sed -iउन चीजों में से किसी को भी संरक्षित नहीं करता है। मैंने इसे केवल एक फ़ाइल के साथ आज़माया, जो मेरे पास नहीं है, लेकिन एक निर्देशिका में स्थित है जो मैं स्वयं करता हूं, और इसने मुझे फ़ाइल को बदलने की अनुमति दी। प्रतिस्थापन मेरे पास है, मूल स्वामी नहीं।
बरमार

1
@ RalphRönnquist सुनिश्चित करने के लिए, आपको इसे दो चरणों में करना होगा:var=$(< FILE); echo "$FILE" | grep '^"' > FILE
Barmar

1
@ बरमार - आप यह काम नहीं करते - आप भी नहीं जानते कि आपने सफलतापूर्वक इनपुट खोला है। बहुत कम से कम तुम कर सकते हो है v=$(<file)&& printf %s\\n "$v" >file, लेकिन आप भी उपयोग नहीं करते हैं &&। पूछने वाले ने इसे एक स्क्रिप्ट में चलाने के बारे में बात की - एक फ़ाइल को स्वयं के एक हिस्से के साथ ओवरराइट करना। आपको कम से कम यह सत्यापित करने के लिए चाहिए कि आप इनपुट और आउटपुट को सफलतापूर्वक खोल सकते हैं। इसके अलावा, शेल फट सकता है।
15

4

इसी तरह sedकाम करता है। यदि -i(जगह में संपादित करें) के साथ प्रयोग किया जाता है sed, तो संसाधित फ़ाइल की नई सामग्री के साथ एक अस्थायी फ़ाइल बनाई जाती है। समाप्त होने पर sed, अस्थायी के साथ वर्तमान कार्यशील फ़ाइल को बदल देता है। उपयोगिता फ़ाइल को जगह में संपादित नहीं करती है । हर संपादक का व्यवहार ठीक यही है।

यह ऐसा है जैसे आप एक शेल में निम्नलिखित कार्य करते हैं:

sed 'whatever' file >tmp_file
mv tmp_file file

इस बिंदु पर sed, fflush()सिस्टम कॉल के साथ त्रुटि संदेश में उल्लिखित फ़ाइल में बफर डेटा को फ्लश करने की कोशिश करता है :

आउटपुट स्ट्रीम के fflush()लिए, दिए गए आउटपुट के लिए सभी उपयोगकर्ता-स्पेस बफ़र किए गए डेटा को लिखने या स्ट्रीम के अंतर्निहित लेखन फ़ंक्शन के माध्यम से अपडेट स्ट्रीम को बाध्य करता है।


आपकी समस्या के लिए, मैं एक सेपरेट फाइलसिस्टम को माउंट करने में एक समाधान देखता हूं (उदाहरण के लिए tmpfs, यदि आपके पास पर्याप्त मेमोरी है, या एक बाहरी स्टोरेज डिवाइस है) और कुछ फाइलों को वहां ले जाएं, उन्हें वहां प्रोसेस करें, और उन्हें वापस ले जाएं।


3

इस प्रश्न को पोस्ट करने के बाद से मैंने सीखा है कि exएक POSIX- आज्ञाकारी कार्यक्रम है। यह लगभग सार्वभौमिक रूप से सहमी हुई है vim, लेकिन किसी भी तरह से, निम्नलिखित है (मुझे लगता है) exफाइलसिस्टम के संबंध में एक महत्वपूर्ण बिंदु है (पोसिक्स विनिर्देश से लिया गया):

यह खंड वर्तमान कार्यशील पाठ का वर्णन करने के लिए शब्द संपादन बफर का उपयोग करता है । इस शब्द से कोई विशेष कार्यान्वयन निहित नहीं है। सभी संपादन परिवर्तन संपादन बफ़र पर किए जाते हैं, और इसमें कोई भी परिवर्तन तब तक किसी फ़ाइल को प्रभावित नहीं करेगा जब तक कि संपादक कमांड फ़ाइल नहीं लिखता।

"... किसी भी फ़ाइल को प्रभावित करेगा ..." मेरा मानना ​​है कि फाइलसिस्टम पर कुछ डालना (बिल्कुल, यहां तक ​​कि एक अस्थायी फ़ाइल) "किसी भी फ़ाइल को प्रभावित करने के रूप में" गिना जाएगा। शायद?*

पाया ऑनलाइन के सामान्य स्क्रिप्टेड उपयोगों की तुलना में (जो कि विशिष्ट कमांड से अटे पड़े हैं ) की तुलना में अपने इच्छित पोर्टेबल उपयोग के बारे में कुछ "गोच" इंगित करने के लिए पोसिक्स विनिर्देशोंex का सावधानीपूर्वक अध्ययन ।exvim

  1. +cmdPOSIX के अनुसार क्रियान्वयन वैकल्पिक है।
  2. कई -cविकल्प देना भी वैकल्पिक है।
  3. वैश्विक कमांड :gअगले गैर-बची हुई न्यूलाइन के लिए सब कुछ "खाती है" (और इसलिए इसे प्रत्येक मैच के बाद चलता है जो रेगेक्स के लिए अंत में एक बार के बजाय पाया जाता है)। तो -c 'g/regex/d | x'केवल एक उदाहरण को हटाता है और फिर फ़ाइल से बाहर निकलता है।

तो मैंने जो शोध किया है, उसके अनुसार, एक विशिष्ट रेगेक्स से मेल खाने वाली सभी लाइनों को हटाने के लिए एक पूर्ण फाइल सिस्टम पर एक फ़ाइल को संपादित करने के लिए POSIX- अनुरूप विधि, है:

ex -sc 'g/myregex/d
x' /path/to/file/filename

यह आपको एक बफर में फ़ाइल को लोड करने के लिए पर्याप्त मेमोरी प्रदान करने वाला काम करना चाहिए।

* यदि आपको कोई ऐसी चीज़ मिलती है जो अन्यथा इंगित करती है, तो कृपया टिप्पणियों में इसका उल्लेख करें।


2
लेकिन पूर्व tmpfiles को लिखता है ... हमेशा। समय-समय पर डिस्क पर अपने बफ़र्स लिखने के लिए इसका नमूना है। डिस्क पर tmp फ़ाइल बफ़र्स का पता लगाने के लिए भी विशिष्ट आदेश हैं।
मोकेसर

@Wildcard साझा करने के लिए धन्यवाद, मैंने SO पर समान पोस्ट पर वापस लिंक किया है । मुझे लगता है ex +g/match/d -scx fileकि POSIX- अनुरूप भी है?
kenorb

@kenorb, काफी नहीं, चश्मे के मेरे पढ़ने के अनुसार - ऊपर दिए गए उत्तर में मेरी बात 1 देखें। POSIX से सटीक उद्धरण है "पूर्व उपयोगिता XBD उपयोगिता सिंटैक्स दिशानिर्देशों के अनुरूप होगी, '-' के अनिर्दिष्ट उपयोग के अलावा, और उस '+' को एक विकल्प सीमांकक के रूप में '' 'के रूप में मान्यता दी जा सकती है ।"
वाइल्डकार्ड

1
मैं इसे सामान्य ज्ञान की अपील के अलावा साबित नहीं कर सकता, लेकिन मेरा मानना ​​है कि आप विनिर्देश से उस बयान में अधिक पढ़ रहे हैं जो वास्तव में है। मेरा सुझाव है कि सुरक्षित व्याख्या यह है कि संपादन सत्र शुरू होने से पहले मौजूद उपयोगकर्ता या नाम वाले किसी भी फ़ाइल को संपादित बफ़र में कोई परिवर्तन प्रभावित नहीं करेगा। मेरे जवाब पर मेरी टिप्पणियाँ भी देखें।
जी-मैन का कहना है कि 'मोनिका'

@ जी-मैन, मुझे वास्तव में लगता है कि आप सही हैं; मेरी प्रारंभिक व्याख्या शायद इच्छाधारी सोच थी। हालाँकि, फ़ाइल को पूर्ण फाइलसिस्टम पर vi काम करने के बाद से संपादित करना , मेरा मानना ​​है कि ज्यादातर मामलों में यह साथ exही साथ काम करेगा - हालांकि शायद एक गिन्नॉर्मस फाइल के लिए नहीं। sed -iफ़ाइलों की परवाह किए बिना एक पूर्ण फाइल सिस्टम पर काम नहीं करता है।
वाइल्डकार्ड

2

पाइप का उपयोग करें, ल्यूक!

फाइल पढ़ें | फ़िल्टर | वापस लिखना

sed 's/PATTERN//' BIGFILE | dd of=BIGFILE conv=notrunc

इस मामले में sedएक नई फ़ाइल नहीं बनाता है और सिर्फ वही फाइलdd खोलने के लिए आउटपुट आउटपुट भेजता है । बेशक एक grepविशेष मामले में उपयोग कर सकते हैं

grep -v 'PATTERN' BIGFILE | dd of=BIGFILE conv=notrunc

तो काटना शेष।

dd if=/dev/null of=BIGFILE seek=1 bs=BYTES_OF_SED_OUTPUT

1
क्या आपने सवाल का "पूर्ण फाइल सिस्टम" नोटिस किया था ?
वाइल्डकार्ड

1
@Wildcard, sedहमेशा अस्थायी फ़ाइलों का उपयोग करता है ? grepवैसे भी नहीं
लेबेन ग्लीबेन

यह spongeकमांड का विकल्प लगता है । हाँ, sedके साथ -iहमेशा lilke 000 अधिकारों के साथ "seduyUdmw" फ़ाइलें बनाता है।
पाब्लो ए

1

जैसा कि अन्य उत्तरों में उल्लेख किया गया है, sed -iफ़ाइल को उसी निर्देशिका में एक नई फ़ाइल में कॉपी करके काम करता है , प्रक्रिया में परिवर्तन करता है, और फिर मूल पर नई फ़ाइल को स्थानांतरित करता है। इसलिए यह काम नहीं करता है।  ed(मूल पंक्ति संपादक) कुछ इसी तरह से काम करता है, लेकिन, पिछली बार जब मैंने जाँच की थी, तो यह /tmpस्क्रैच फ़ाइल के लिए उपयोग करता है । यदि आपका /tmpभरा हुआ फाइल सिस्टम अलग है, edतो वह आपके लिए काम कर सकता है।

इसे आज़माएं (अपने इंटरैक्टिव शेल प्रॉम्प्ट पर):

$ ed / path / to / file / filename
पी
g / myregex / d
w
क्ष

P(जो एक है राजधानी पी) सख्ती से आवश्यक नहीं है। यह संकेत देता है; इसके बिना, आप अंधेरे में काम कर रहे हैं, और कुछ लोगों को यह पता चलता है। wऔर qकर रहे हैं डब्ल्यू संस्कार और क्ष UIT।

edगुप्त निदान के लिए कुख्यात है। यदि किसी भी बिंदु पर यह कुछ और प्रदर्शित करता है जो शीघ्र (जो है *) या ऐसा कुछ जो स्पष्ट रूप से सफल संचालन की पुष्टि है ( विशेषकर यदि इसमें शामिल है ?), फ़ाइल (साथ ) लिखें w। बस छोड़ दिया ( q)। यदि यह आपको बाहर निकलने नहीं देता है, तो qफिर से कहने का प्रयास करें।

यदि आपकी /tmpनिर्देशिका फाइलसिस्टम पर है जो भरी हुई है (या यदि उसका फाइलसिस्टम भरा हुआ है, तो भी), तो कहीं न कहीं जगह खोजने की कोशिश करें। अव्यवस्था बढ़ते एक tmpfs या एक बाहरी भंडारण उपकरण (उदाहरण के लिए, एक फ्लैश ड्राइव) का उल्लेख किया; लेकिन, यदि आपके पास कई फाइल सिस्टम हैं, और वे सभी पूर्ण नहीं हैं , तो आप बस एक मौजूदा अन्य का उपयोग कर सकते हैं। अराजकता फ़ाइल (ओं) को अन्य फाइल सिस्टम पर sedकॉपी करने, उन्हें वहां (साथ ) संपादित करने और फिर उन्हें कॉपी करने का सुझाव देती है। इस बिंदु पर, यह सबसे सरल समाधान हो सकता है। लेकिन एक विकल्प एक फाइलसिस्टम पर एक लिखने योग्य निर्देशिका बनाना होगा जिसमें कुछ खाली जगह होगी, TMPDIRउस निर्देशिका को इंगित करने के लिए पर्यावरण चर सेट करें , और फिर चलाएं ed। (प्रकटीकरण: मुझे यकीन नहीं है कि यह काम करेगा, लेकिन यह चोट नहीं पहुँचा सकता है।)

एक बार जब आप edकाम कर लेते हैं , तो आप इसे करके स्वचालित कर सकते हैं

एड फ़ाइल नाम << EOF
g / myregex / d
w
क्ष
EOF

एक स्क्रिप्ट में। या , जैसा कि don_crissti द्वारा सुझाया गया है।printf '%s\n' 'g/myregex/d' w q | ed -s filename


हममम। क्या एक ही चीज की जा सकती है (या तो edया इसके साथ ex) ऐसी मेमोरी का उपयोग एक अलग फाइल सिस्टम के बजाय किया जाता है? यही कारण है कि मैं वास्तव में के लिए जा रहा था (और कारण है कि मैं एक जवाब स्वीकार नहीं किया है।)
वाइल्डकार्ड

हम्म। यह मेरे द्वारा महसूस किए जाने से अधिक जटिल हो सकता है। मैंने edकई साल पहले बड़े पैमाने पर स्रोत का अध्ययन किया था। 16-बिट कंप्यूटर के रूप में अभी भी ऐसी चीजें थीं, जिन पर प्रक्रियाएं 64K (!) पते की जगह तक सीमित थीं, इसलिए संपूर्ण फ़ाइल को मेमोरी में पढ़ने वाले संपादक का विचार एक गैर-स्टार्टर था। तब से, बेशक, स्मृति बड़ी हो गई है - लेकिन डिस्क और फाइलें हैं। चूंकि डिस्क इतनी बड़ी हैं, इसलिए लोगों /tmpको अंतरिक्ष से बाहर भागने की आकस्मिकता से निपटने की आवश्यकता महसूस नहीं होती है। मैंने अभी हाल के संस्करण के स्रोत कोड पर एक त्वरित नज़र edडाली, और यह अभी भी लगता है ... (Cont'd)
G-Man Says 'Reinstate Monica'

(Cont'd) ... बिना किसी अस्थायी फ़ाइल के "बफर संपादित करें" को लागू करने के लिए - और मुझे कोई संकेत नहीं मिल सकता है कि ed( exया vi) का कोई भी संस्करण बफर को स्मृति में रखने का विकल्प प्रदान करता है।  दूसरी ओर, एड और vi के साथ टेक्स्ट एडिटिंग - अध्याय 11: टेक्स्ट प्रोसेसिंग - भाग II: रेड हैट लिनक्स की खोज - Red Hat Linux 9 प्रोफेशनल सीक्रेट - लिनक्स सिस्टम का कहना है कि ed'बफर एडिटिंग मेमोरी में रहता है, ... (Cont'd) )
जी-मैन का कहना है कि 'मोनिका'

(Cont'd)… और बालासुब्रमण्यम श्रीनिवासन द्वारा UNIX डॉक्यूमेंट प्रोसेसिंग और टाइपसेटिंग के बारे में एक ही बात कहती है vi(जो कि जैसा प्रोग्राम है ex)। मेरा मानना ​​है कि वे केवल मैला, आवेगपूर्ण शब्द का उपयोग कर रहे हैं - लेकिन, अगर यह इंटरनेट पर है (या प्रिंट में), यह सही होना चाहिए, है ना? आप अपने पैसे का भुगतान करते हैं और आप अपनी पसंद लेते हैं।
जी-मैन का कहना है कि 'मोनिका'

लेकिन फिर भी, मैंने एक नया उत्तर जोड़ा है।
जी-मैन का कहना है कि 'मोनिका'

1

आप फ़ाइल को बहुत आसानी से काट सकते हैं यदि आप अपने ऑफसेट को बाइट की गिनती प्राप्त कर सकते हैं और आपकी लाइनें प्रारंभ बिंदु से अंत तक हो सकती हैं।

o=$(sed -ne'/regex/q;p' <file|wc -c)
dd if=/dev/null of=file bs="$o" seek=1

या फिर अगर आपका ${TMPDIR:-/tmp}किसी और फाइल सिस्टम पर है तो शायद:

{   cut -c2- | sed "$script" >file
} <file <<FILE
$(paste /dev/null -)
FILE

क्योंकि (अधिकांश) गोले अपने यहां-दस्तावेजों को हटाए गए अस्थायी-फ़ाइल में डालते हैं। यह पूरी तरह से सुरक्षित है जब तक कि <<FILEडिस्क्रिप्टर शुरू से अंत तक बनाए रखा जाता है और आपके ${TMPDIR:-/tmp}पास जितनी आवश्यकता होती है उतनी जगह होती है।

शेल जो अस्थायी फ़ाइलों का उपयोग नहीं करते हैं वे पाइप का उपयोग करते हैं, और इसलिए इस तरह से उपयोग करना सुरक्षित नहीं है। ये गोले आम तौर पर कर रहे हैं ashकी तरह डेरिवेटिव busybox, dashबीएसडी sh- zsh, bash, ksh, और बॉर्न शैल, हालांकि, सभी उपयोग अस्थायी फ़ाइलें।

स्पष्ट रूप से मैंने पिछले जुलाई में थोड़ा सा शेल प्रोग्राम लिखा था ताकि कुछ ऐसा किया जा सके


यदि /tmpव्यवहार्य नहीं है, तो जब तक आप फ़ाइल को स्मृति में फिट कर सकते हैं जैसे कि ...

sed 'H;$!d;x' <file | { read v &&
sed "$script" >file;}

... एक सामान्य मामले के रूप में कम से कम यह सुनिश्चित करना होगा कि फ़ाइल को sedपहले / आउट फ़ाइल को छोटा करने का प्रयास करने से पहले पूरी तरह से बफ़र किया गया था ।

एक और अधिक लक्षित और कुशल - समाधान हो सकता है:

sed '/regex/!H;$!d;x' <file|{ read v && cat >file;}

... क्योंकि यह बफ़रिंग लाइनों को परेशान नहीं करेगा जो आप वैसे भी हटाना चाहते थे।

सामान्य मामले की एक परीक्षा:

{   nums=/tmp/nums
    seq 1000000 >$nums
    ls -lh "$nums"
    wc -l  "$nums"
    sed 'H;$!d;x' <$nums | { read script &&  ### read always gets a blank
    sed "$script" >$nums;}
    wc -l  "$nums"
    ls -lh "$nums"
}

-rw-r--r-- 1 mikeserv mikeserv 6.6M Dec 22 20:26 /tmp/nums
1000000 /tmp/nums
1000000 /tmp/nums
-rw-r--r-- 1 mikeserv mikeserv 6.6M Dec 22 20:26 /tmp/nums

मैं स्वीकार करता हूं कि मैंने आपके उत्तर को पहले विस्तार से नहीं पढ़ा था, क्योंकि यह अटूट (मेरे लिए) समाधान से शुरू होता है जिसमें बाइट काउंट (कई सर्वरों में से प्रत्येक के बीच भिन्न) और /tmpजो एक ही फाइल सिस्टम पर होता है। मुझे आपका दोहरा sedसंस्करण पसंद है । मुझे लगता है कि बामार का एक संयोजन और आपका उत्तर शायद सबसे अच्छा होगा, कुछ इस तरह से: myvar="$(sed '/myregex/d' < file)" && [ -n "$myvar" ] && echo "$myvar" > file ; unset myvar (इस मामले के लिए मुझे नई रूपरेखाओं को संरक्षित करने की परवाह नहीं है।)
वाइल्डकार्ड

2
@Wildcard - वह हो सकता है। लेकिन आपको किसी डेटाबेस की तरह शेल का उपयोग नहीं करना चाहिए। sed| catऊपर की चीज कभी भी आउटपुट नहीं खोलती है जब तक sedकि पहले से ही पूरी फाइल बफ़र नहीं की गई है और आउटपुट के लिए यह सब लिखना शुरू करने के लिए तैयार है। यदि यह फ़ाइल को बफ़र करने का प्रयास करता है और विफल हो जाता है - readसफल नहीं होता है क्योंकि |पाइप पर ईओएफ पाता है इससे पहले कि यह अपनी पहली नईलाइन पढ़ता है और इसलिए cat >out ऐसा तब तक कभी नहीं होता है जब तक कि इसे पूरी तरह से मेमोरी से बाहर लिखने का समय न हो। एक अतिप्रवाह या ऐसा कुछ भी बस विफल हो जाता है। यह भी कि पूरी पाइपलाइन हर बार सफलता या विफलता देती है। इसे एक संस्करण में संग्रहीत करना अधिक जोखिम भरा है।
mikeserv

@Wildcard - अगर मैं वास्तव में इसे एक चर में भी चाहता था, तो मुझे लगता है कि आईडी इसे पसंद करती है: file=$(sed '/regex/!H;$!d;x' <file | read v && tee file) && cmp - file <<<"$file" || shiteइसलिए आउटपुट फ़ाइल और संस्करण एक साथ लिखा जाएगा, जो या तो या एक प्रभावी बैकअप बना देगा, जो एकमात्र कारण है जिसे आप चाहते हैं जिन चीजों की आपको आवश्यकता होगी, उनसे अधिक जटिल।
mikeserv

@ बाइक: मैं अब ओपी के रूप में एक ही समस्या से निपट रहा हूं और मुझे आपका समाधान वास्तव में उपयोगी लगता है। लेकिन मैं का उपयोग समझ में नहीं आता read scriptऔर read vअपने जवाब में। यदि आप इसके बारे में अधिक विस्तार से बता सकते हैं तो मुझे बहुत सराहना मिलेगी, धन्यवाद!
sylye

1
@sylye - $scriptवह sedस्क्रिप्ट है जिसे आप अपनी फ़ाइल के किसी भी हिस्से को लक्षित करने के लिए उपयोग करेंगे; इसकी स्क्रिप्ट जो आपको अंतिम परिणाम देती है, जिसे आप स्ट्रीम में चाहते हैं। vएक खाली लाइन के लिए बस एक प्लेसहोल्डर है। एक bashशेल में यह आवश्यक नहीं है क्योंकि यदि आप एक निर्दिष्ट नहीं करते हैं, तो bashस्वचालित रूप से $REPLYशेल चर का स्वचालित रूप से उपयोग करेगा , लेकिन पॉस्ली आपको हमेशा ऐसा होना चाहिए। मुझे खुशी है कि आप इसे उपयोगी पाते हैं, वैसे। इसके साथ गुड लक। im mikeserv @ gmail अगर आपको गहराई में कुछ भी चाहिए। मेरे पास कुछ दिनों में फिर से एक कंप्यूटर होना चाहिए
mikeserv

0

यह उत्तर इस अन्य उत्तर और इस अन्य उत्तर से विचारों को उधार लेता है, लेकिन उन पर बनाता है, एक ऐसा उत्तर बनाता है जो अधिक सामान्यतः लागू होता है:

num_bytes = $ (sed '/ myregex / d' / path / to / file / filen | wc -c)
sed '/ myregex / d' / path / to / file / filename 1 <> / path / to / file / filename 
dd if = / dev / null of = / path / to / file / filename bs = $ num_bytes "की तलाश करें = 1

पहली पंक्ति sedमानक आउटपुट के लिए लिखे गए आउटपुट के साथ कमांड चलाती है (और एक फ़ाइल के लिए नहीं); विशेष रूप से, wcपात्रों को गिनने के लिए एक पाइप के लिए । दूसरी पंक्ति भी sedमानक आउटपुट के लिए लिखे गए आउटपुट के साथ कमांड को चलाती है , जो इस मामले में इनपुट फाइल को रीड / राइट ओवरराइट (कोई ट्रंकट) मोड में रीडायरेक्ट नहीं किया जाता है, जिसकी चर्चा यहां की गई है । यह कुछ हद तक खतरनाक बात है; यह तभी सुरक्षित होता है जब फ़िल्टर कमांड कभी भी डेटा (पाठ) की मात्रा नहीं बढ़ाता है; यानी, प्रत्येक n बाइट्स के लिए जिसे वह पढ़ता है, वह n या कम बाइट्स लिखता है । यह निश्चित रूप से, sed '/myregex/d'कमांड के लिए सही है ; प्रत्येक पंक्ति के लिए जिसे वह पढ़ता है, वह सटीक एक ही पंक्ति, या कुछ भी नहीं लिखता है। (अन्य लेख:s/foo/fu/या s/foo/bar/सुरक्षित होगा, लेकिन s/fu/foo/और s/foo/foobar/नहीं होगा।)

उदाहरण के लिए:

$ cat filename
It was
a dark and stormy night.
$ sed '/was/d' filename 1<> filename
$ cat filename
a dark and stormy night.
night.

क्योंकि डेटा के इन 32 बाइट्स:

I  t     w  a  s \n  a     d  a  r  k     a  n  d     s  t  o  r  m  y     n  i  g  h  t  . \n

इन 25 पात्रों के साथ ओवरराइट किया गया:

a     d  a  r  k     a  n  d     s  t  o  r  m  y     n  i  g  h  t  . \n

सात बाइट्स night.\nको अंत में छोड़ दिया।

अंत में, ddकमांड नए, स्क्रब किए गए डेटा (इस उदाहरण में बाइट 25) के अंत की तलाश करता है और शेष फ़ाइल को हटा देता है; अर्थात, यह उस बिंदु पर फ़ाइल को काट देता है।


यदि, किसी भी कारण से, 1<>चाल काम नहीं करती है, तो आप कर सकते हैं

sed '/ myregex / d' / path / to / file / filename | dd of = / path / to / file / filename conv = notrunc

यह भी ध्यान दें कि, जब तक आप कर रहे हैं सभी लाइनों को हटा रहे हैं, आप सभी की जरूरत है grep -v myregex(के रूप में Barmar द्वारा बताया गया है )।


-3

sed -i 'd' / path / to / file / filename


1
नमस्ते! यह सबसे अच्छा होगा कि जितना विस्तार से समझाया जाए उतना ही प्रासंगिक है कि आपका समाधान कैसे काम करता है और सवाल का जवाब देता है।
ढग

2
यह एक भयानक गैर-जवाब है। (ए) यह एक पूर्ण फाइलसिस्टम पर विफल होगा, ठीक मेरे मूल आदेश की तरह; (b) यदि यह सफल हुआ, तो यह मेरे रेलेक्स से मेल खाने वाली लाइनों के बजाय WHOLE फ़ाइल को खाली कर देगा।
वाइल्डकार्ड
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.