मेरे पास एक निर्देशिका में कई पाठ फाइलें हैं, और मैं निर्देशिका में हर फाइल की अंतिम पंक्ति को हटाना चाहता हूं।
मैं यह कैसे कर सकता हूं?
मेरे पास एक निर्देशिका में कई पाठ फाइलें हैं, और मैं निर्देशिका में हर फाइल की अंतिम पंक्ति को हटाना चाहता हूं।
मैं यह कैसे कर सकता हूं?
जवाबों:
यदि आप GNU है तो आप इस अच्छे oneliner का उपयोग कर सकते हैं sed
।
sed -i '$ d' ./*
यह वर्तमान निर्देशिका में प्रत्येक गैर-छिपी फ़ाइल की अंतिम पंक्ति को हटा देगा। -i
जीएनयू के लिए स्विच का sed
मतलब है जगह में काम करना और अंतिम पंक्ति ( मतलब अंतिम और अर्थ हटाना) को हटाने की '$ d'
आज्ञा देना ।sed
$
d
-i
वह प्रयोग कर रहे हैं जो एक GNUism है, इसलिए यह लूट है, लेकिन मैं अपनी पुरानी दाढ़ी को खड़ा कर दूंगा अगर मैं यह बताने में विफल रहा कि कुछ पुराने संस्करण sed
आपको $
और d
(या) के बीच कोई व्हाट्सएप नहीं डालने देंगे । सामान्य तौर पर, पैटर्न और कमांड के बीच)।
*(.)
नियमित फ़ाइलों के लिए ग्लोब का उपयोग कर सकते हैं , मुझे अन्य गोले के बारे में पता नहीं है।
अन्य जवाबों में सभी समस्याएँ हैं यदि निर्देशिका में एक नियमित फ़ाइल के अलावा कुछ है, या फ़ाइल नाम में रिक्त स्थान / newlines के साथ एक फ़ाइल है। यहाँ कुछ है जो परवाह किए बिना काम करता है:
find "$dir" -type f -exec sed -i '$d' '{}' '+'
find "$dir" -type f
: निर्देशिका में फ़ाइलों को खोजें $dir
-type f
जो नियमित फाइलें हैं;-exec
प्रत्येक फ़ाइल पर कमांड निष्पादित करेंsed -i
: फ़ाइलों को जगह में संपादित करें;'$d'
: d
अंतिम ( $
) लाइन को हटाएं ( ) ।'+'
: बताता है कि तर्क जोड़ना जारी रखें sed
(प्रत्येक फ़ाइल के लिए कमांड चलाने की तुलना में थोड़ा अधिक कुशल, @zwol के लिए धन्यवाद)।आप उपनिर्देशिकाएं में उतर नहीं करना चाहते हैं, तो आप तर्क जोड़ सकते हैं -maxdepth 1
करने के लिए find
।
find
अधिक कुशलता से लिखे गए हैं find $dir -type f -exec sed -i '$d' '{}' '+'
।)
-print0
पूर्ण आदेश में मौजूद नहीं है, इसे स्पष्टीकरण में क्यों रखा गया है?
-depth 0
काम नहीं करता है (खोज 4.4.2), यह इसके बजाय होना चाहिए -maxdepth 1
।
-exec
।
जीएनयू sed -i '$d'
का उपयोग करने का मतलब है कि पूरी फ़ाइल को पढ़ना और अंतिम पंक्ति के बिना उसकी एक प्रतिलिपि बनाना, जबकि यह फ़ाइल को जगह में कम करने के लिए (कम से कम बड़ी फ़ाइलों के लिए) बहुत अधिक कुशल होगा।
GNU के साथ truncate
, आप यह कर सकते हैं:
for file in ./*; do
[ -f "$file" ] &&
length=$(tail -n 1 "$file" | wc -c) &&
[ "$length" -gt 0 ] &&
truncate -s "-$length" "$file"
done
यदि फाइलें अपेक्षाकृत छोटी हैं, तो यह संभवतः कम कुशल होगी क्योंकि यह प्रति फ़ाइल कई कमांड चलाती है।
ध्यान दें कि अंतिम नई लाइन वर्ण (अंतिम पंक्ति के बाद) के बाद या दूसरे शब्दों में यदि वे गैर-सीमांकित अंतिम पंक्ति के बाद अतिरिक्त बाइट्स वाली फ़ाइलों के लिए हैं , तो tail
कार्यान्वयन के आधार पर , tail -n 1
केवल उन अतिरिक्त बाइट्स (जैसे GNU tail
) को वापस कर देंगे , या अंतिम (ठीक से सीमांकित) लाइन और उन अतिरिक्त बाइट्स।
|wc -c
में tail
कॉल? (या a ${#length}
)
${#length}
यह काम नहीं करेगा क्योंकि यह वर्णों को गिनता है, बाइट्स नहीं करता है और $(...)
टेलिंग न्यूलाइन वर्ण को हटा देगा, ${#...}
भले ही सभी वर्ण एकल-बाइट हों।
एक अधिक पोर्टेबल दृष्टिकोण:
for f in ./*
do
test -f "$f" && ed -s "$f" <<\IN
d
w
q
IN
done
मुझे नहीं लगता कि इसके लिए किसी स्पष्टीकरण की आवश्यकता है ... सिवाय इसके कि शायद इस मामले d
में भी यही है $d
क्योंकि ed
डिफ़ॉल्ट रूप से अंतिम पंक्ति का चयन होता है।
यह पुनरावर्ती खोज नहीं करेगा और छिपी हुई फ़ाइलों (उर्फ डॉटफ़ाइल्स) को संसाधित नहीं करेगा।
यदि आप उन लोगों को भी संपादित करना चाहते हैं, तो एक निर्देशिका के अंदर छिपी हुई फ़ाइलों के साथ * मिलान कैसे करें देखें
[[]]
हैं []
तो यह पूरी तरह से POSIX आज्ञाकारी होगा। ( [[ ... ]]
बैशिज़्म है।)
[[
एक बशीवाद नहीं है )
POSIX- कम्पाइलेंट एक-लाइनर सभी फाइलों के लिए पुनरावर्ती रूप से वर्तमान निर्देशिका में शुरू होता है, जिसमें डॉट-फाइलें भी शामिल हैं:
find . -type f -exec sh -c 'for f; do printf "\$d\nx\n" | ex "$f"; done' sh {} +
.txt
केवल गैर-पुनरावर्ती फ़ाइलों के लिए :
find . -path '*/*/*' -prune -o -type f -name '*.txt' -exec sh -c 'for f; do printf "\$d\nx\n" | ex "$f"; done' sh {} +
और देखें: