จะพิมพ์คอลัมน์ที่สามเป็นคอลัมน์สุดท้ายได้อย่างไร?


121

ฉันกำลังพยายามลบสองคอลัมน์แรก (ซึ่งฉันไม่สนใจ) ออกจากไฟล์บันทึก DbgView ดูเหมือนจะไม่พบตัวอย่างที่พิมพ์ตั้งแต่คอลัมน์ 3 เป็นต้นไปจนถึงท้ายบรรทัด โปรดทราบว่าแต่ละบรรทัดมีจำนวนคอลัมน์ที่แปรผัน


คำตอบ:


108

... หรือวิธีแก้ปัญหาที่ง่ายกว่านั้น: cut -f 3- INPUTFILE เพียงแค่เพิ่มตัวคั่นที่ถูกต้อง (-d) และคุณจะได้รับเอฟเฟกต์เดียวกัน


9
โปรดทราบว่าสิ่งนี้ใช้ได้เฉพาะเมื่อตัวคั่นเหมือนกันทุกประการระหว่างคอลัมน์ทั้งหมด ... ตัวอย่างเช่นคุณไม่สามารถใช้การตัดกับตัวคั่นเช่น \ d + (ที่ฉันรู้)
Zach Wily

72
เมื่อคำถามมีชื่อว่า awk ไม่เหมาะสมที่จะยอมรับคำตอบอื่นที่ไม่ใช่ awk จะเกิดอะไรขึ้นถ้าผู้คนต้องการมันสำหรับสคริปต์ awk? คำตอบนี้ควรเป็นเพียงความคิดเห็น
syaz

24
@SyaZ: ปกติฉันจะเห็นด้วย แต่ด้วยจำนวนของ 'awk ที่ไม่จำเป็น' ที่เกิดขึ้นบนกระดานนี้ฉันคิดว่าจำเป็นต้องแสดงวิธีอื่นในการทำงานนี้ คุณจะไม่ขอบคุณถ้ามีคนแสดงให้คุณเห็นวิธีที่ง่ายและรวดเร็วกว่าในการทำงานเดียวกัน? ผู้โพสต์อาจคิดว่า awk เป็นวิธีเดียวที่จะทำเช่นนี้เนื่องจากจำนวนคำตอบที่ 'ไม่ถูกต้อง แต่ไม่น่าจะเป็นไปได้' สำหรับคำถามอื่น ๆ ?
Marcin

12
นั่นคือสิ่งที่แสดงความคิดเห็นเพื่อ ยอมรับคำตอบ awk ที่ดีที่สุดและให้คำแนะนำที่ดีกว่าสำหรับความคิดเห็น หากผู้คนเริ่มโพสต์คำตอบที่ไม่ตรงคำถามมันจะน่ารำคาญเมื่อค้นหา (ในกรณีของฉัน)
syaz

12
ไม่เพียง แต่ตัวคั่นจะต้องเหมือนกันระหว่างคอลัมน์ทั้งหมดเท่านั้น แต่ต้องมีอักขระตัวคั่นระหว่างคอลัมน์อย่างแน่นอน ดังนั้นหากคุณกำลังจัดการกับโปรแกรมที่จัดเรียงเอาต์พุตด้วยตัวคั่นควรใช้ awk ดีกว่า
sknaumov

112
awk '{for(i=3;i<=NF;++i)print $i}' 

3
awk '{for (i = 3; i <= NF; ++ i) print $ i}' มีขนาดกะทัดรัดมากขึ้น :)
user172818

1
ขอบคุณ lh3 ฉันแค่คัดลอกและวางสำหรับคู่มือ gawk :)
Jonathan Feinberg

23
สิ่งนี้ล้มเหลวด้วยหลายบรรทัดแต่ละคอลัมน์จะถูกแบ่งเป็นบรรทัดใหม่เมื่อพิมพ์
iwth

13
เพื่อแก้ไขปัญหาเอาต์พุตที่แยกออกฉันขอเสนอวิธีแก้ปัญหานี้: awk '{for(i=3;i<=NF;++i)printf $i""FS ; print ""}'( printfจะไม่พิมพ์อักขระขึ้นบรรทัดใหม่ในขณะที่print ""จะเพิ่มบรรทัดใหม่หลังจากพิมพ์ฟิลด์อื่นแล้ว)
lauhub

1
หรือ: echo $(seq 1 10) | awk '{for (i=3; i<=NF; i++) printf $i FS}'ซึ่งให้: 3 4 5 6 7 8 9 10.
x-yuri

106
awk '{ print substr($0, index($0,$3)) }'

พบวิธีแก้ปัญหาที่นี่:
http://www.linuxquestions.org/questions/linux-newbie-8/awk-print-field-to-end-and-character-count-179078/


23
ฉันมาสายสำหรับเรื่องนี้ แต่สิ่งนี้ใช้ไม่ได้กับระเบียนที่ฟิลด์แรกหรือฟิลด์ที่สองเท่ากับฟิลด์ที่สาม (เช่น 3 2 3 4 5)
aleph_null

สามารถพิมพ์ช่วงภายในได้: `` # จาก $ 3 (รวม) ถึง $ 6 (ไม่รวม); เสียงสะท้อน "1,2,3,4,5,6,7,8,9" | awk 'BEGIN {FS = ","; OFS = ","} {print substr ($ 0, index ($ 0, $ 3), length ($ 0) -index ($ 0, $ 6) -1)}'; # ให้ 3,4,5```
splaisan

34

คำตอบของJonathan Feinbergจะพิมพ์แต่ละฟิลด์ในบรรทัดแยกกัน คุณสามารถใช้printfเพื่อสร้างเรกคอร์ดใหม่สำหรับเอาต์พุตในบรรทัดเดียวกัน แต่คุณสามารถย้ายฟิลด์ข้ามไปทางซ้ายได้

awk '{for (i=1; i<=NF-2; i++) $i = $(i+2); NF-=2; print}' logfile

1
โปรดทราบว่าสิ่งนี้ใช้ได้กับ Gnu awk เท่านั้นNFPOSIX ไม่อนุญาตให้ลดค่าใช้จ่าย
kvantour

1
@kvantour: ทำงานใน gawk, mawk, MacOS awk (nawk?) POSIX ดูเหมือนจะเงียบว่าNFสามารถลดลงได้หรือไม่
หยุดชั่วคราวจนกว่าจะมีประกาศอีกครั้ง

มันเป็นหนึ่งในเหล่านี้ตลกมุมมืดของ awk
kvantour

19
awk '{$1=$2=$3=""}1' file

หมายเหตุ: วิธีนี้จะปล่อย "ช่องว่าง" ไว้ในช่อง 1,2,3 แต่ไม่ใช่ปัญหาหากคุณต้องการดูผลลัพธ์


ติดตามคำสั่งนั้นด้วย `| sed s / ^ \ * // | คอลัมน์ -t` เพื่อตัดช่องว่างนำหน้าและจัดแนวคอลัมน์ที่เหลือ
MSpreij

สุดท้าย1หมายถึงอะไร? ฉันควรค้นหาด้วยคำหลักawkใด
Itachi

@ อิทาจิดูตัวอย่างที่ 1 ของcatonmat.net/blog/awk-one-liners-explained-part-one
kvantour

1
@ นาธานคุณแก้ปัญหานี้เมื่อ{$1=$2=$3="";$0=$0;$1=$1}1
kvantour

11

หากคุณต้องการพิมพ์คอลัมน์หลังจากที่ 3 เช่นในบรรทัดเดียวกันคุณสามารถใช้:

awk '{for(i=3; i<=NF; ++i) printf "%s ", $i; print ""}'

ตัวอย่างเช่น:

Mar 09:39 20180301_123131.jpg
Mar 13:28 20180301_124304.jpg
Mar 13:35 20180301_124358.jpg
Feb 09:45 Cisco_WebEx_Add-On.dmg
Feb 12:49 Docker.dmg
Feb 09:04 Grammarly.dmg
Feb 09:20 Payslip 10459 %2828-02-2018%29.pdf

มันจะพิมพ์:

20180301_123131.jpg
20180301_124304.jpg
20180301_124358.jpg
Cisco_WebEx_Add-On.dmg
Docker.dmg
Grammarly.dmg
Payslip 10459 %2828-02-2018%29.pdf

อย่างที่เราเห็นสลิปเงินเดือนแม้จะมีช่องว่างก็แสดงในบรรทัดที่ถูกต้อง


รวดเร็วและทันสมัย ขอบคุณ;)
9nz9

ยอดเยี่ยมมากยกเว้นว่าฉันมีปัญหากับ $ NF ที่ถูกยกเว้น เมื่อฉันตั้งเงื่อนไข (<= NF) ฉันได้รับฟิลด์สุดท้าย แต่อักขระตัวแรกของฟิลด์แรกถูกตัดออก ฉันเข้าใจผิดในแง่ของฟังก์ชันการทำงานหรือไม่?
Ken Ingram

ดูเหมือนว่าปัญหาของฉันคือ ^ M ติดอยู่ที่ท้ายคอลัมน์สุดท้าย ไม่เห็นวิธีการเอาออก
Ken Ingram

8

สิ่งที่เกี่ยวกับบรรทัดต่อไปนี้:

awk '{$ 1 = $ 2 = $ 3 = ""; print} 'ไฟล์

ตามคำแนะนำของ @ ghostdog74 ของฉันควรทำงานได้ดีขึ้นเมื่อคุณกรองบรรทัดกล่าวคือ:

awk '/ ^ exim4-config / {$ 1 = ""; print} 'ไฟล์

สั้นและเรียบง่าย นอกจากนี้ยังสามารถsed 's/\s\+//g'
ไพพ์

8
awk -v m="\x0a" -v N="3" '{$N=m$N ;print substr($0, index($0,m)+1)}'

สิ่งนี้จะตัดสิ่งที่อยู่ก่อนฟิลด์ที่กำหนด nr., N และพิมพ์ส่วนที่เหลือทั้งหมดของบรรทัดรวมถึงฟิลด์ nr.N และการรักษาระยะห่างเดิม (จะไม่ฟอร์แมตใหม่) มันจะไม่แปรสภาพถ้าสตริงของฟิลด์ปรากฏที่อื่นในบรรทัดด้วยซึ่งเป็นปัญหากับคำตอบของ daisaa

กำหนดฟังก์ชัน:

fromField () { 
awk -v m="\x0a" -v N="$1" '{$N=m$N; print substr($0,index($0,m)+1)}'
}

และใช้มันดังนี้:

$ echo "  bat   bi       iru   lau bost   " | fromField 3
iru   lau bost   
$ echo "  bat   bi       iru   lau bost   " | fromField 2
bi       iru   lau bost 

เอาท์พุทรักษาทุกอย่างรวมถึงช่องว่างต่อท้าย

ใช้งานได้ดีกับไฟล์ที่ '/ n' เป็นตัวคั่นบันทึกดังนั้นคุณจึงไม่มีอักขระขึ้นบรรทัดใหม่ภายในบรรทัด หากคุณต้องการใช้ร่วมกับตัวคั่นบันทึกอื่น ๆ ให้ใช้:

awk -v m="\x01" -v N="3" '{$N=m$N ;print substr($0, index($0,m)+1)}'

ตัวอย่างเช่น. ทำงานได้ดีกับไฟล์เกือบทั้งหมดตราบเท่าที่ไม่ได้ใช้เลขฐานสิบหกถ่าน nr 1 ภายในเส้น


4

คำสั่ง awk ต่อไปนี้จะพิมพ์ฟิลด์ N สุดท้ายของแต่ละบรรทัดและในตอนท้ายของบรรทัดจะพิมพ์อักขระบรรทัดใหม่:

awk '{for( i=6; i<=NF; i++ ){printf( "%s ", $i )}; printf( "\n"); }'

ค้นหาด้านล่างตัวอย่างที่แสดงรายการเนื้อหาของไดเร็กทอรี / usr / bin จากนั้นเก็บ 3 บรรทัดสุดท้ายจากนั้นพิมพ์ 4 คอลัมน์สุดท้ายของแต่ละบรรทัดโดยใช้ awk:

$ ls -ltr /usr/bin/ | tail -3
-rwxr-xr-x 1 root root       14736 Jan 14  2014 bcomps
-rwxr-xr-x 1 root root       10480 Jan 14  2014 acyclic
-rwxr-xr-x 1 root root    35868448 May 22  2014 skype

$ ls -ltr /usr/bin/ | tail -3 | awk '{for( i=6; i<=NF; i++ ){printf( "%s ", $i )}; printf( "\n"); }'
Jan 14 2014 bcomps 
Jan 14 2014 acyclic 
May 22 2014 skype

4
awk '{a=match($0, $3); print substr($0,a)}'

อันดับแรกคุณจะพบตำแหน่งของจุดเริ่มต้นของคอลัมน์ที่สาม ด้วย Substr คุณจะพิมพ์ทั้งบรรทัด ($ 0) โดยเริ่มจากตำแหน่ง (ในกรณีนี้ a) ไปยังจุดสิ้นสุดของบรรทัด


3

คุณสามารถทำเอฟเฟกต์เดียวกันได้อย่างง่ายดายโดยใช้นิพจน์ทั่วไป สมมติว่าตัวคั่นเป็นช่องว่างมันจะมีลักษณะดังนี้:

awk '{ sub(/[^ ]+ +[^ ]+ +/, ""); print }'

1
ฉันจะหลีกเลี่ยง regex อาจจะช้ากว่าและง่ายกว่าที่จะทำเลอะโดยไม่ตั้งใจ
Cascabel

1
มันทำให้สั้นลงแบบนี้awk '{ sub(/([^ ]+ +){2}/, ""); print }'ซึ่งจะใช้รูปแบบห่างออกไปสองเท่า
erik


2

โซลูชัน Perl:

perl -lane 'splice @F,0,2; print join " ",@F' file

ใช้ตัวเลือกบรรทัดคำสั่งเหล่านี้:

  • -n วนรอบทุกบรรทัดของไฟล์อินพุตอย่าพิมพ์ทุกบรรทัดโดยอัตโนมัติ

  • -l ลบบรรทัดใหม่ก่อนประมวลผลและเพิ่มกลับเข้าไปในภายหลัง

  • -aโหมด autosplit - แยกบรรทัดอินพุตลงในอาร์เรย์ @F ค่าเริ่มต้นคือการแบ่งช่องว่าง

  • -e ดำเนินการรหัส perl

splice @F,0,2 ลบคอลัมน์ 0 และ 1 ออกจากอาร์เรย์ @F อย่างหมดจด

join " ",@F รวมองค์ประกอบของอาร์เรย์ @F โดยใช้ช่องว่างระหว่างแต่ละองค์ประกอบ

หากไฟล์อินพุตของคุณคั่นด้วยจุลภาคแทนที่จะใช้การคั่นด้วยช่องว่างให้ใช้ -F, -lane


โซลูชัน Python:

python -c "import sys;[sys.stdout.write(' '.join(line.split()[2:]) + '\n') for line in sys.stdin]" < file


1

ที่นี่สายไปหน่อย แต่ดูเหมือนจะไม่ได้ผล ลองใช้วิธีนี้โดยใช้ printf แทรกช่องว่างระหว่างแต่ละอัน ฉันเลือกที่จะไม่ขึ้นบรรทัดใหม่ในตอนท้าย

awk '{for(i=3;i<=NF;++i) printf("%s ",  $i) }'

1
awk '{for (i=4; i<=NF; i++)printf("%c", $i); printf("\n");}'

พิมพ์บันทึกโดยเริ่มจากฟิลด์ที่ 4 ไปยังฟิลด์สุดท้ายตามลำดับเดียวกันกับที่อยู่ในไฟล์ต้นฉบับ


ขออภัยนี่ไม่ใช่คำตอบที่ถูกต้อง มันเจาะจงเกินไป แต่ฉันไม่รู้จะลบอย่างไร
Massimo


0

หากเป็นเพียงการละเว้นสองฟิลด์แรกและหากคุณไม่ต้องการช่องว่างเมื่อกำบังฟิลด์เหล่านั้น (เช่นเดียวกับคำตอบด้านบนบางคำ):

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

0
awk '{$1=$2=""}1' FILENAME | sed 's/\s\+//g'

สองคอลัมน์แรกถูกล้างsedเอาช่องว่างนำหน้าออก


-2

ในคอลัมน์ AWK เรียกว่าฟิลด์ดังนั้น NF จึงเป็นกุญแจสำคัญ

ทุกแถว:

awk -F '<column separator>' '{print $(NF-2)}' <filename>

แถวแรกเท่านั้น:

awk -F '<column separator>' 'NR<=1{print $(NF-2)}' <filename>
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.