कैसे एक सीएसवी फ़ाइल के साथ छेड़खानी करने के लिए sed या awk?


23

मैं निम्नलिखित CSV फ़ाइल का उपयोग करके sedया कैसे कर सकता हूँ awk?

  • एक कॉलम हटाएं
  • एक कॉलम डुप्लिकेट करें
  • एक स्तंभ ले जाएँ

मेरे पास 200 से अधिक पंक्तियों के साथ एक बड़ी तालिका है, और मैं इससे परिचित नहीं हूं sed


1
AskUbuntu
enzotib

@enzotib क्या आप लिंक पोस्ट कर सकते हैं?
n0pe

@MaxMackie askubuntu.com/questions/88142/... । मुझे इस समय वहाँ एक मॉड का सामना नहीं करना पड़ सकता है, इसलिए मैंने इसे ध्वजांकित किया और उनसे पूछा कि क्या वे तैयार हैं; यह पहले से ही स्वीकृत उत्तर नहीं है तो मुझे यकीन है कि अगर वे करेंगे नहीं कर रहा हूँ
माइकल Mrozek

@MichaelMrozek, हम्मम, आमतौर पर इन स्थितियों में क्या होता है? क्या हम केवल डुप्लिकेट रखते हैं?
n0pe

1
जब तक आपको एक ऐसे सिस्टम पर चलने की आवश्यकता नहीं है जिसमें केवल बुनियादी उपकरण उपलब्ध हैं, तो देखें कि क्या सीएसवी फाइलों को संसाधित करने के लिए एक मजबूत कमांड लाइन उपकरण है?
गिल्स एसओ- बुराई को रोकें

जवाबों:


7

खेतों को कैसे काटें और फिर से व्यवस्थित करें (अन्य उत्तरों में कवर) के अलावा, quirky CSV फ़ील्ड का मुद्दा है।

यदि आपका डेटा इस "quirky" श्रेणी में आता है, तो पूर्व और पोस्ट फ़िल्टरिंग का थोड़ा ध्यान रखा जा सकता है। नीचे दिखाया गया फिल्टर की आवश्यकता होती है वर्ण \x01, \x02, \x03, \x04आपके डेटा में कहीं भी दिखाई नहीं करने के लिए।

यहाँ फिल्टर को साधारण awkफ़ील्ड डंप के चारों ओर लपेटा गया है ।

नोट: फ़ील्ड-पाँच में एक अमान्य / अपूर्ण "उद्धृत फ़ील्ड" लेआउट है, लेकिन यह पंक्ति के अंत में (CSV पार्सर के आधार पर) सौम्य है। लेकिन, निश्चित रूप से, यह समस्याग्रस्त unexpedted परिणाम का कारण होगा अगर इसे अपने वर्तमान अंत पंक्ति स्थिति से दूर स्वैप किया जाना था ।

अद्यतन करें; जब एक अल्पविराम अनुगामी उद्धरण से पहले user121196 ने एक बग को इंगित किया है। यहाँ तय है।

आँकड़े

cat <<'EOF' >file
field one,"fie,ld,two",field"three","field,\",four","field,five
"15111 N. Hayden Rd., Ste 160,",""
EOF

कोड

sed -r 's/^/,/; s/\\"/\x01/g; s/,"([^"]*)"/,\x02\1\x03/g; s/,"/,\x02/; :MC; s/\x02([^\x03]*),([^\x03]*)/\x02\1\x04\2/g; tMC; s/^,// ' file |
  awk -F, '{ for(i=1; i<=NF; i++) printf "%s\n", $i; print NL}' |
    sed -r 's/\x01/\\"/g; s/(\x02|\x03)/"/g; s/\x04/,/g' 

उत्पादन:

field one
"fie,ld,two"
field"three"
"field,\",four"
"field,five

"15111 N. Hayden Rd., Ste 160,"
""

यहाँ पूर्व फ़िल्टर है , टिप्पणियों के साथ विस्तारित किया गया है। पोस्ट फिल्टर बस के विपरीत है । , ,
\x01\x02\x03\x04

sed -r '
    s/^/,/                # add a leading comma delimiter
    s/\\"/\x01/g          # obfuscate escaped quotation-mark (\")
    s/,"([^"]*)"/,\x02\1\x03/g    # obfuscate quotation-marks
    s/,"/,\x02/           # when no trailing quote on last field  
    :MC                   # obfuscate commas embedded in quotes
    s/\x02([^\x03]*),([^\x03]*)/\x02\1\x04\2/g
    tMC
    s/^,//                # remove spurious leading delimiter
'

आप इस फ़िल्टर के आधार पर nth कॉलम को कैसे हटाएंगे?
user121196

@ user121196 - जैसा कि इसके शुरुआती वाक्य में बताया गया है, यह उत्तर CSV डेटा को अधिक सुसंगत बनाने का एक तरीका दिखाता है .. जैसे। एक भावपूर्ण टोकन चरित्र के साथ एक उद्धरण-एम्बेडेड अल्पविराम की जगह पर… और फिर इसे चाल / कट / हटाए जाने के बाद अल्पविराम में बदल दिया। फिर से, जैसा कि उल्लेख किया गया है, चाल / कट / डिलीट स्टेप को साधारण awk फील्ड-डंप द्वारा बदल दिया जाता है
पीटर।

1
यह इस मामले में विफल रहता है: "15111 एन। हेडन Rd।, Ste 160,", ""
user121196

@ user121196: इसे इंगित करने के लिए धन्यवाद। मैंने उत्तर को एक फिक्स के साथ अपडेट किया है।
पीटर।

15

यह इस बात पर निर्भर करता है कि क्या आपका CSV फ़ाइल केवल सीमांकक का उपयोग करता है, या यदि आपके पास पागलपन है:

फ़ील्ड एक, "फ़ील्ड, दो", फ़ील्ड तीन

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

एक कॉलम हटाना

आप एकल कॉलम से कई तरह से छुटकारा पा सकते हैं; मैंने उदाहरण के रूप में कॉलम 2 का उपयोग किया। सबसे आसान तरीका संभवतः उपयोग करना है cut, जो आपको एक सीमांकक निर्दिष्ट करता है -dऔर आप किन क्षेत्रों को प्रिंट करना चाहते हैं -f; यह इसे कॉमा और आउटपुट फ़ील्ड 1 पर विभाजित करने के लिए कहता है, और फ़ील्ड 3 अंत के माध्यम से:

$ cut -d, -f1,3- /path/to/your/file

यदि आपको वास्तव में उपयोग करने की आवश्यकता है sed, तो आप एक नियमित अभिव्यक्ति लिख सकते हैं जो पहले n-1क्षेत्रों, nवें क्षेत्र और बाकी से मेल खाती है , और nवें को आउटपुट करना छोड़ें (यहां n2 है, इसलिए पहले समूह का मिलान 1समय पर किया जाता है:) \{1\}:

$ sed 's/\(\([^,]\+,\)\{1\}\)[^,]\+,\(.*\)/\1\3/' /path/to/your/file

ऐसा करने के कई तरीके हैं awk, उनमें से कोई भी विशेष रूप से सुरुचिपूर्ण नहीं है। आप एक forलूप का उपयोग कर सकते हैं , लेकिन अनुगामी अल्पविराम से निपटना एक दर्द है; यह देखते हुए कि यह कुछ इस तरह होगा:

$ awk -F, '{for(i=1; i<=NF; i++) if(i != 2) printf "%s,", $i; print NL}' /path/to/your/file

मुझे फ़ील्ड 1 आउटपुट करना आसान लगता है और फिर substrफ़ील्ड 2 के बाद सब कुछ बंद करने के लिए उपयोग करना चाहिए:

$ awk -F, '{print $1 "," substr($0, length($1)+length($2)+3)}' /path/to/your/file

यह हालांकि आगे स्तंभों के लिए कष्टप्रद है

एक कॉलम डुप्लिकेट करना

इसमें sedअनिवार्य रूप से पहले की तरह ही अभिव्यक्ति होती है, लेकिन आप लक्ष्य स्तंभ पर भी कब्जा कर लेते हैं और उस समूह को प्रतिस्थापन में कई बार शामिल करते हैं:

$ sed 's/\(\([^,]\+,\)\{1\}\)\([^,]\+,\)\(.*\)/\1\3\3\4/' /path/to/your/file

में awkपाश रास्ता के लिए यह कैसा (फिर अनुगामी अल्पविराम अनदेखी) कुछ हो जाएगा:

$ awk -F, '{
for(i=1; i<=NF; i++) {
    if(i == 2) printf "%s,", $i;
    printf "%s,", $i
}
print NL
}' /path/to/your/file

जिस substrतरह से:

$ awk -F, '{print $1 "," $2 "," substr($0, length($1)+2)}' /path/to/your/file

(tcdyl उनके जवाब में एक बेहतर विधि के साथ आया )

एक कॉलम आगे बढ़ रहा है

मुझे लगता है कि sedसमाधान दूसरों से स्वाभाविक रूप से अनुसरण करता है, लेकिन यह हास्यास्पद रूप से लंबा होना शुरू हो जाता है


यह एक भरा हुआ जवाब है! +1 :)
जयपाल सिंह

हास्यास्पद लंबे समय तक? पाह !
गिल्स एसओ- बुराई को रोकें

12

awkतुम्हारा सबसे अच्छा दांव है। awkखेतों को संख्या से प्रिंट करता है, इसलिए ...

awk 'BEGIN { FS=","; OFS=","; } {print $1,$2,$3}' file

किसी कॉलम को निकालने के लिए, उसे प्रिंट न करें:

 awk 'BEGIN { FS=","; OFS=","; } {print $1,$3}' file

आदेश बदलने के लिए:

awk 'BEGIN { FS=","; OFS=","; } {print $3,$1,$2}' file

आउटपुट फ़ाइल पर फिर से निर्देशित करें।

awk 'BEGIN { FS=","; OFS=","; } {print $3,$1,$2}' file > output.file

awk आउटपुट को भी प्रारूपित कर सकते हैं।

अघ प्रारूप आउटपुट


चूंकि यह CSV है, इसलिए आपको इसकी आवश्यकता भी होगी BEGIN { FS=","; OFS=","; }

1
मुझे लगता है कि एफएस = ओएफएस = "," भी काम करेगा।

5

निम्नलिखित प्रारूप में एक स्थान-सीमांकित फ़ाइल को देखते हुए:

1 2 3 4 5

आप फ़ील्ड 2 को awk जैसे हटा सकते हैं:

awk '{ sub($2,""); print}' file

जो लौटता है

1  3 4 5

कॉलम 2 को कॉलम n से बदलें जहाँ उपयुक्त हो।

कॉलम 2 को डुप्लिकेट करने के लिए,

awk '{ col = $2 " " $2; $2 = col; print }' file

जो लौटता है

1 2 2 3 4 5

कॉलम 2 और 3 को स्विच करने के लिए,

awk '{temp = $2; $2 = $3; $3 = temp; print}'

जो लौटता है

1 3 2 4 5

awk आमतौर पर खेतों की अवधारणा से निपटने में बहुत अच्छा है । यदि आप CSV के साथ काम कर रहे हैं, और स्पेस-सीमांकित फ़ाइल नहीं है, तो आप बस उपयोग कर सकते हैं

awk -F,

अपने क्षेत्र को अल्पविराम के रूप में परिभाषित करने के लिए, स्थान के बजाय (जो डिफ़ॉल्ट है)। ऑनलाइन कई अच्छे awk संसाधन हैं, जिनमें से एक को मैं नीचे दिए गए स्रोत के रूप में सूचीबद्ध करता हूं।

# 3 के लिए स्रोत


मैं बहुत बारे में पता नहीं है awk, लेकिन यह उत्पादन करने लगता है अंतरिक्ष से अलग की गई है, भले ही क्षेत्र विभाजक है ,(क्षेत्र-विभाजक बस नियंत्रण कैसे यह इनपुट के प्रबंधन)
माइकल Mrozek

@MichaelMrozek: हाँ, यह OFS awk वेरिएबल है जो आउटपुट फील्ड सेपरेटर को नियंत्रित करता है।
enzotib

हां, और जैसा कि मैंने अपने जवाब में उल्लेख किया है, आप सीमांकक को बदलने के लिए -F विकल्प को पास कर सकते हैं (उदाहरण -F,)
tcdyl

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.