ฉันจะทำสิ่งต่อไปนี้กับไฟล์ CSV โดยใช้sed
หรือawk
?
- ลบคอลัมน์
- ทำซ้ำคอลัมน์
- ย้ายคอลัมน์
ฉันมีโต๊ะใหญ่กว่า 200 sed
แถวและฉันไม่ว่าคุ้นเคยกับ
ฉันจะทำสิ่งต่อไปนี้กับไฟล์ CSV โดยใช้sed
หรือawk
?
ฉันมีโต๊ะใหญ่กว่า 200 sed
แถวและฉันไม่ว่าคุ้นเคยกับ
คำตอบ:
นอกเหนือจากวิธีการตัดและจัดเรียงเขตข้อมูลอีกครั้ง (ครอบคลุมในคำตอบอื่น ๆ ) มีปัญหาของเขตข้อมูล CSV ที่เล่นโวหาร
หากข้อมูลของคุณอยู่ในหมวดหมู่ "แปลกประหลาด" การกรองล่วงหน้าและโพสต์เล็กน้อยสามารถดูแลได้ ฟิลเตอร์ที่แสดงด้านล่างต้องใช้ตัวละคร\x01
, \x02
, \x03
, \x04
ไม่ปรากฏที่ใดก็ได้ในข้อมูลของคุณ
นี่คือตัวกรองที่ล้อมรอบการawk
ถ่ายโอนข้อมูล แบบง่าย
หมายเหตุ: ฟิลด์ห้ามีเลย์เอาต์ "เขตข้อมูลที่อ้างถึง" ไม่ถูกต้อง / ไม่สมบูรณ์ แต่จะมีรูปแบบที่ไม่เป็นทางการที่ส่วนท้ายของแถว (ขึ้นอยู่กับตัวแยกวิเคราะห์ CSV) แต่แน่นอนว่ามันจะทำให้เกิดผลลัพธ์ที่ยังไม่ได้ชำระที่มีปัญหาหากต้องสลับออกจากตำแหน่งสิ้นสุดแถวปัจจุบัน
อัปเดต; 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
'
ขึ้นอยู่กับว่าไฟล์ CSV ของคุณใช้เครื่องหมายจุลภาคสำหรับตัวคั่นเท่านั้นหรือหากคุณมีความบ้าคลั่งเช่น:
ฟิลด์หนึ่ง, "ฟิลด์สอง", ฟิลด์สาม
สิ่งนี้ถือว่าคุณกำลังใช้ไฟล์ CSV ง่ายๆ:
คุณสามารถกำจัดคอลัมน์เดียวได้หลายวิธี ฉันใช้คอลัมน์ 2 เป็นตัวอย่าง วิธีที่ง่ายที่สุดน่าจะเป็นในการใช้งานcut
ซึ่งจะช่วยให้คุณระบุตัวคั่น-d
และเขตข้อมูลที่คุณต้องการพิมพ์-f
; สิ่งนี้บอกให้แยกบนคอมม่าและฟิลด์เอาต์พุต 1 และฟิลด์ 3 ถึงจุดสิ้นสุด:
$ cut -d, -f1,3- /path/to/your/file
หากคุณต้องการใช้งานจริงsed
คุณสามารถเขียนนิพจน์ทั่วไปที่ตรงกับn-1
ฟิลด์แรกฟิลด์n
th และส่วนที่เหลือและข้ามการแสดงผลลัพธ์n
th (นี่n
คือ 2 ดังนั้นกลุ่มแรกจะจับคู่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
วิธีการแก้ปัญหาเป็นไปตามธรรมชาติจากที่อื่น ๆ แต่มันก็เริ่มที่จะเยาะเย้ยนาน
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
สามารถจัดรูปแบบผลลัพธ์เช่นกัน
กำหนดไฟล์ที่คั่นด้วยช่องว่างในรูปแบบต่อไปนี้:
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
แต่ดูเหมือนว่าจะแยกช่องว่างออกแม้ว่าตัวคั่นฟิลด์จะเป็น,
( ตัวคั่นฟิลด์จะควบคุมวิธีการจัดการอินพุต)
มันจะใช้งานได้สำหรับการลบ
awk '{$2="";$0=$0;$1=$1}1'
อินพุต
a b c d
เอาท์พุต
a c d