फ़ाइल को लाइनों से कैसे काटें?


13

मेरे पास बड़ी संख्या में फ़ाइल है, जिनमें से कुछ बहुत लंबी हैं। अगर वे फ़ाइल के अंत को हटाकर बड़े होते हैं तो मैं उन्हें एक निश्चित आकार में काट देना चाहूंगा। लेकिन मैं केवल पूरी लाइनें निकालना चाहता हूं। मैं यह कैसे कर सकता हूँ? ऐसा लगता है कि लिनक्स टूलचैन द्वारा नियंत्रित किया जाएगा, लेकिन मुझे सही कमांड का पता नहीं है।

उदाहरण के लिए, मान लें कि मेरे पास 300-बाइट लाइनों के साथ 120,000 बाइट फ़ाइल है और मैं इसे 10,000 बाइट्स में विभाजित करने का प्रयास कर रहा हूं। पहले 33 लाइनों को रहना चाहिए (9900 बाइट्स) और शेष को काट देना चाहिए। मैं 10,000 बाइट्स बिल्कुल नहीं काटना चाहता, क्योंकि यह एक आंशिक रेखा छोड़ देगा।

बेशक फाइलें अलग-अलग लंबाई की हैं और लाइनें सभी समान लंबाई की नहीं हैं।

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


मेरा उत्तर हटा दिया गया ... मुझे लगता है कि बाइट्स में फ़ाइल का आकार बहुत स्पष्ट नहीं था, क्षमा करें। हो सकता है कि आप अपने प्रश्न को संपादित कर सकें और उस भाग को स्पष्ट कर सकें (उदाहरण के साथ)?
slhck

@ एलएलएचके: क्षमा करें, आपको यह देखने के लिए कि मैं अस्पष्ट था, क्योंकि मैं इसे ठीक कर सकता हूं।
चार्ल्स

कोई चिंता नहीं, मैं ऐसे ही पूछ लिया जाना चाहिए था, खेद :)
slhck

जवाबों:


1

sed/ wcजटिलता पिछले जवाब में बचा जा सकता है अगर awkप्रयोग किया जाता है। ओपी से प्रदान किए गए उदाहरण का उपयोग करना ( 10000 बाइट्स से पहले पूरी लाइनें दिखाना ):

awk '{i += (length() + 1); if (i <= 10000) print $ALL}' myfile.txt

साथ ही यदि बाइट लाइन के अंत में नहीं है तो 10000 वीं बाइट वाली पूरी लाइन दिखाना:

awk '{i += (length() + 1); print $ALL; if (i >= 10000) exit}' myfile.txt

उत्तर ऊपर माना जाता है:

  1. टेक्स्ट फ़ाइल यूनिक्स लाइन टर्मिनेटर ( \n) की है। DOS / Windows पाठ फ़ाइलें (के लिए \r\n), परिवर्तन length() + 1करने के लिएlength() + 2
  2. पाठ फ़ाइल में केवल एकल बाइट वर्ण होता है। यदि मल्टीबाइट चरित्र (जैसे यूनिकोड पर्यावरण के तहत) है, तो LC_CTYPE=Cबाइट स्तर पर व्याख्या को बाध्य करने के लिए वातावरण सेट करें ।

15

sedदृष्टिकोण ठीक है, लेकिन सभी लाइनों पर पाश करने के लिए नहीं है। यदि आप जानते हैं कि आप कितनी लाइनें रखना चाहते हैं (उदाहरण के लिए, मैं यहां 99 का उपयोग करता हूं), तो आप इसे इस तरह से कर सकते हैं:

sed -i '100,$ d' myfile.txt

स्पष्टीकरण: sedएक नियमित अभिव्यक्ति प्रोसेसर है। -iदिए गए विकल्प के साथ , यह सीधे एक फ़ाइल ("इनलाइन") को संसाधित करता है - केवल इसे पढ़ने और मानक आउटपुट पर परिणाम लिखने के बजाय। 100,$बस का अर्थ है "लाइन 100 से फ़ाइल के अंत तक" - और इसके बाद कमांड है d, जिसे आपने संभवतः "हटाएं" के लिए खड़े होने का अनुमान लगाया है। तो संक्षेप में, कमांड का अर्थ है: "myfile.txt से फ़ाइल के अंत तक लाइन 100 से सभी लाइनें हटाएं"। 100 डिलीट होने वाली पहली लाइन है, क्योंकि आप 99 लाइन रखना चाहते हैं।

संपादित करें: यदि, दूसरी ओर, लॉग फाइलें हैं जहां आप अंतिम 100 पंक्तियों को रखना चाहते हैं:

[ $(wc -l myfile.txt) -gt 100 ] && sed -i "1,$(($(wc -l myfile.txt|awk '{print $1}') - 100)) d" myfile.txt

यहाँ क्या हो रहा है:

  • [ $(wc -l myfile.txt) -gt 100 ]: केवल तभी करें जब फ़ाइल में 100 से अधिक लाइनें हों
  • $((100 - $(wc -l myfile.txt|awk '{print $1}')))हटाने के लिए लाइनों की संख्या की गणना (यानी फ़ाइल के सभी लाइनों को छोड़कर (अंतिम) 100 रखने के लिए)
  • 1, $((..)) d: गणना की गई पहली पंक्ति से सभी लाइनों को हटा दें

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

  • एक विशिष्ट आकार फ़ाइल के साथ रहेगा (10,000 बाइट्स)
  • प्रत्येक पंक्ति में बाइट्स में एक विशिष्ट आकार होता है (उदाहरण में 300 बाइट्स)

इन आंकड़ों से "/" के रूप में बने रहने के लिए लाइनों की संख्या की गणना करना संभव है, जिसका उदाहरण 33 लाइनों का मतलब होगा। गणना के लिए शैल शब्द: $((size_to_remain / linesize))(कम से कम बश का उपयोग करके लिनक्स पर, परिणाम एक पूर्णांक है)। समायोजित कमांड अब पढ़ा जाएगा:

# keep the start of the file (OPs question)
sed -i '34,$ d' myfile.txt
# keep the end of the file (my second example)
[ $(wc -l myfile.txt) -gt 33 ] && sed -i "1,33 d" myfile.txt

जैसा कि आकार पहले से जाना जाता है, sedकमांड में एम्बेडेड गणना की अब कोई आवश्यकता नहीं है । लेकिन लचीलेपन के लिए, कुछ शेल स्क्रिप्ट के अंदर कोई भी चर का उपयोग कर सकता है।

फ़ाइल आकार के आधार पर सशर्त प्रसंस्करण के लिए, कोई भी "परीक्षण" के बाद वें का उपयोग कर सकता है:

[ "$(ls -lk $file | awk ' {print $5}')" -gt 100 ] &&

जिसका अर्थ है: "यदि आकार $file100kB से अधिक है, तो ..." ( ls -lkस्थिति 5 में kB में फ़ाइल का आकार सूचीबद्ध करता है, इसलिए awkइसका उपयोग वास्तव में करने के लिए किया जाता है)।


ओपी एक निश्चित बाइट के आकार के आधार पर फ़ाइल में कटौती करना चाहता है - न केवल लाइनों के संदर्भ में लंबाई। मैंने अपना उत्तर शामिल कर हटा दिया head -n
19

@slhck अधिसूचना के लिए धन्यवाद। हां, ओपी ने सिर्फ इस सवाल को संपादित किया ताकि इरादा और अधिक स्पष्ट हो सके। जैसा कि उसके पास प्रत्येक पंक्ति में कितने बाइट्स की गणना करने का मतलब है, मेरा जवाब सिद्धांत रूप में मान्य है - क्योंकि वह लाइनों की संख्या की गणना कर सकता है, और फिर फ़ाइलों को संभालने के लिए मेरे दृष्टिकोण का उपयोग करें। हो सकता है कि मैं अपने उत्तर में उस पर एक छोटी टिप्पणी करूं।
इज़्ज़ी

नहीं - आकार पहले से ज्ञात नहीं हैं। वह एक उदाहरण था। प्रत्येक फ़ाइल का एक अलग आकार होगा और लाइनें अनियमित लंबाई की होंगी। कुछ फ़ाइलों को बिल्कुल भी अलग करने की आवश्यकता नहीं है।
चार्ल्स

ओह, फिर से ... खैर, कुछ चीजों को स्पष्ट रूप से (बहुत सारे पहलुओं को) स्पष्ट करना मुश्किल है। उन फ़ाइलों के लिए जिन्हें ट्रंकट की आवश्यकता नहीं है, यह संभवतः फ़ाइल आकार पर आधारित है? वह ढंका जा सकता है। लेकिन अगर एक औसत लाइन आकार भी ज्ञात नहीं है, तो यह हिस्सा कठिन हो जाता है - मैं इस समय एक आसान समाधान (बहुत अधिक ओवरहेड के बिना) के बारे में नहीं सोच सकता।
इज़्ज़ी

वर्तमान में मैं सभी के साथ आ सकता हूं, जैसे कि पहली एन लाइनें प्राप्त करना, उनके आधार पर औसत लंबाई की गणना करना और इस मान का उपयोग करना। क्या इससे आपको मदद मिलेगी?
इज़्ज़ी

0

ऐसा करने की आज्ञा पाने में विफल, मैंने एक त्वरित स्क्रिप्ट लिखी (परीक्षण नहीं):

#!/bin/sh

# Usage: $0 glob.* 25000
# where glob.* is a wildcard pattern and 25000 is the maximum number of bytes.

limit=20000
tmp=/tmp/trim
[[ "$2" == +([0-9]) ]] || limit=$2
limit=`expr $len + 1`
for file in $1;
do
    [[ `wc -c $file` -lt $limit ]] && continue
    head -c $file > $tmp
    sed '$d' $tmp
    $tmp > $file
done

-1

आप किसी फ़ाइल से लाइनें निकालने के लिए linux कमांड sed का उपयोग कर सकते हैं। निम्न आदेश फ़ाइल नाम की अंतिम पंक्ति को हटा दें।

sed '$d' filename.txt

Awk या खोजने से आप अपने sed कमांड के लिए मैच करने वाले पैटर्न की खोज कर सकते हैं। सबसे पहले आप awk से सर्च करें या उन फाइल्स को खोजें जिन्हें आप छोटा करना चाहते हैं और फिर आप sed वाली लाइनों को हटा सकते हैं।


-1

मैंने पूंछ के साथ कुछ ऐसा ही किया। इस मामले में केवल अंतिम 10,000 लाइनें रखने के लिए:

TMP=$(tail -n 10000 /path/to/some/file 2>/dev/null) && echo "${TMP}" > /path/to/some/file
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.