ฉันจะทำสิ่งต่อไปนี้กับไฟล์ 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ฟิลด์แรกฟิลด์nth และส่วนที่เหลือและข้ามการแสดงผลลัพธ์nth (นี่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/filesubstrวิธี:
$ 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.fileawk สามารถจัดรูปแบบผลลัพธ์เช่นกัน 
กำหนดไฟล์ที่คั่นด้วยช่องว่างในรูปแบบต่อไปนี้:
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 5awk โดยทั่วไปดีมากที่จัดการกับแนวคิดของสาขา หากคุณกำลังจัดการกับ CSV และไม่ใช่ไฟล์ที่มีการเว้นวรรคคุณสามารถใช้
awk -F,เพื่อกำหนดเขตข้อมูลของคุณเป็นเครื่องหมายจุลภาคแทนที่จะเว้นวรรค (ซึ่งเป็นค่าเริ่มต้น) มีทรัพยากร awk ที่ดีจำนวนหนึ่งซึ่งหนึ่งในนั้นเป็นรายการด้านล่าง
แหล่งที่มาสำหรับ # 3
awkแต่ดูเหมือนว่าจะแยกช่องว่างออกแม้ว่าตัวคั่นฟิลด์จะเป็น,( ตัวคั่นฟิลด์จะควบคุมวิธีการจัดการอินพุต)
                    มันจะใช้งานได้สำหรับการลบ
awk '{$2="";$0=$0;$1=$1}1'อินพุต
a b c dเอาท์พุต
a c d