จะพิมพ์คอลัมน์ทั้งหมดหลังตัวเลขโดยใช้ awk ได้อย่างไร


90

บนเชลล์ฉันจะไปที่ awk เมื่อฉันต้องการคอลัมน์ใดคอลัมน์หนึ่ง

สิ่งนี้พิมพ์คอลัมน์ 9 ตัวอย่างเช่น:

... | awk '{print $9}'

ฉันจะบอกให้ awk พิมพ์คอลัมน์ทั้งหมดรวมทั้งและหลังคอลัมน์ 9ไม่ใช่เฉพาะคอลัมน์ 9 ได้อย่างไร


คำตอบ:


83
awk '{ s = ""; for (i = 9; i <= NF; i++) s = s $i " "; print s }'

3
การปรับแต่งเล็กน้อย:awk -v N=9 '{sep=""; for (i=N; i<=NF; i++) {printf("%s%s",sep,$i); sep=OFS}; printf("\n")}'
glenn jackman

ขอบคุณ @glenn นั่นเป็นเรื่องทั่วไปกว่าเล็กน้อย อย่างไรก็ตาม - ฉันเห็นด้วยอย่างแน่นอนว่าควรใช้cutหรือperlเพื่อสิ่งนี้ ใช้สิ่งนี้ก็ต่อเมื่อคุณยืนยันที่จะมีเข้ามาawkจริงๆ
Amadan

1
@SiegeX: ไม่ได้เพิ่ม NUL ไบต์ แต่จะปล่อย FS ไว้ระหว่างแต่ละฟิลด์ว่าง
Dennis Williamson

1
โปรดดูคำตอบของ @ Ascherer เพื่อความสง่างาม

3
@veryhungrymike: ความสง่างามเป็นสิ่งที่ดี แต่ฉันควรจะถูกต้อง : p
Amadan

68

เมื่อคุณต้องการทำหลายช่องawkไม่มีวิธีตรงไปตรงมาในการทำเช่นนี้ ฉันอยากจะแนะนำcutแทน:

cut -d' ' -f 9- ./infile

แก้ไข

เพิ่มตัวคั่นช่องว่างเนื่องจากค่าเริ่มต้นเป็นแท็บ ขอบคุณ Glenn ที่ชี้ให้เห็นสิ่งนี้


15
สิ่งหนึ่งเกี่ยวกับการตัดคือการใช้ตัวคั่นเฉพาะ (แท็บโดยค่าเริ่มต้น) โดยที่ awk ใช้ "ช่องว่าง" ด้วยการตัดแท็บ 2 แท็บติดต่อกันจะคั่นช่องว่าง
glenn jackman

1
ดังที่ @glennjackman ชี้ให้เห็นตัวคั่นของ awk คือ "ช่องว่าง" (จำนวนเท่าใดก็ได้เช่นกัน) ดังนั้นการตั้งค่าตัวคั่นการตัดเป็นช่องว่างเดียวจะไม่ตรงกับพฤติกรรมเช่นกัน น่าเสียดายที่การวนซ้ำเป็นสิ่งที่ดีที่สุดที่สามารถทำได้ดังนั้นจึงดูเหมือน
poncha

อันนี้ทำงานไม่ถูกต้อง find . | xargs ls -l | cut -d' ' -f 9-ลองคำสั่ง ด้วยเหตุผลบางประการจะนับช่องว่างสองครั้งด้วย ตัวอย่าง: lrwxrwxrwx 1 me me 21 Dec 12 00:00 ./file_a lrwxrwxrwx 1 me me 64 Dec 6 00:06 ./file_bจะส่งผลให้./file_a 00:06 ./file_b
Marco Pashkov

@MarcoPashkov โปรดละเอียดในหนึ่งนี้ทำงานไม่ถูกต้องโดยเฉพาะการพิจารณาคุณใช้แน่นอนรหัสเดียวกันในท่อของคุณ อย่างไรก็ตามคุณไม่
SiegeX

ตัดไม่ทำงานที่นี่ ตัวอย่างเช่นหากอินพุตของคุณเป็น "foo bar" (ช่องว่างเดียว) สำหรับหนึ่งบรรทัดและ "foo ___ bar" (เช่นช่องว่างหลายช่อง แต่ SO ฉลาดเกินไปที่จะแสดง) สำหรับอีกช่องหนึ่งการตัดจะประมวลผลต่างกัน
UKMonkey

54
awk '{print substr($0, index($0,$9))}'

แก้ไข : หมายเหตุจะใช้ไม่ได้หากฟิลด์ใด ๆ ก่อนที่เก้ามีค่าเดียวกับที่เก้า


10
@veryhungrymike: ... และจะไม่ทำงานหากฟิลด์ใด ๆ ก่อนที่เก้ามีค่าเดียวกับที่เก้า
Amadan

6
อาจเป็นเพราะประโยคคลาสสิก "หวังว่าไฟล์ของคุณจะไม่มีปัญหานั้น" มันเป็นทั้งหมดไม่มีไม่มีใน w / วิศวกรรมเพื่อรัฐ: "เราจะไม่เสียเวลารวมทั้งข้อผิดพลาดในการตรวจสอบสำหรับการป้อนข้อมูลของค่าลบเช่นเพราะ 'เราหวังว่าผู้ใช้จะฉลาดพอที่จะไม่พยายามที่พวกเขาออก ทำให้เครื่องมือของเราพัง "" ฮ่าฮ่าฮ่า! ชอบที่จะได้ยินสิ่งนี้เสมอ! (ผมชอบความรู้สึกที่ดีของอารมณ์ขัน) ดีที่โง่ทำอยู่ก็เป็นหน้าที่ของนักพัฒนาที่จะทำให้สิ่งที่เขางี่เง่าหลักฐาน ! แทนที่จะ "หวังดีกับมนุษย์". นั่นเป็นทัศนคติที่คาดหวังกับนักปรัชญาไม่ใช่วิศวกร s / w ... LOL
syntaxerror

3
ฉันไม่ได้บอกว่าจะไม่ตรวจสอบข้อผิดพลาด แต่ถ้าคุณรู้ว่าคุณจะไม่ประสบปัญหาวิธีนี้ก็ใช้ได้เหมือนที่ฉันระบุไว้ แต่ขอขอบคุณสำหรับการลงคะแนน @syntaxerror ที่ไม่จำเป็น โซลูชันนี้จะใช้ได้กับบางคนเนื่องจาก (ปัจจุบัน) 19 upvotes จะแสดงขึ้น แต่ถ้าไม่เป็นเช่นนั้นก็อย่าใช้กับโซลูชันของคุณ มีหลายวิธีในการแก้ปัญหาของ OP
Ascherer

1
หากคุณใช้ awk ในบรรทัดคำสั่งในการทำงานประจำวันนี่เป็นทางออกที่คุณต้องการอย่างแน่นอน มันไม่ชัดเจน? การตรวจสอบข้อผิดพลาด ฯลฯ ไม่สำคัญในกรณีนั้นเนื่องจากคุณกำลังพิมพ์และสามารถจับสิ่งเหล่านี้ได้ก่อนที่คุณจะกด Enter (โดยส่วนตัวฉันไม่คิดว่าควรใช้ awk สำหรับสิ่งอื่นใดนั่นคือเหตุผลที่เรา 'ได้รับ perl, python, tcl และอื่น ๆ อีกประมาณ 100+ ภาษาดีกว่าเร็วกว่าและน่ารำคาญน้อยกว่า!)' บางทีฉันอาจให้เครดิตกับนักพัฒนาซอฟต์แวร์เพื่อนของฉันมากเกินไปและพวกเขาก็ต้องการการตรวจสอบข้อผิดพลาดแม้กระทั่งในสิ่งที่พวกเขาพิมพ์ ได้ทันที (??)
osirisgothra

1
ไม่ใช่ว่ามันต้องการมันเพราะมันอยู่ด้านล่างคำตอบ แต่ฉันเพิ่ม @atti
Ascherer

11
sed -re 's,\s+, ,g' | cut -d ' ' -f 9-

แทนที่จะจัดการกับช่องว่างความกว้างตัวแปรให้แทนที่ช่องว่างทั้งหมดเป็นช่องว่างเดียว จากนั้นใช้แบบธรรมดาcutกับสาขาที่สนใจ

มันไม่ได้ใช้ awk ดังนั้นจึงไม่ใช่เชื้อโรค แต่ดูเหมือนว่าเหมาะสมเมื่อได้รับคำตอบ / ความคิดเห็นอื่น ๆ


1
โปรดทำให้คำตอบของคุณน่ากลัวมากขึ้นมิฉะนั้นจะโพสต์เป็นความคิดเห็นของคำถาม
Alper Turan

เหมาะสำหรับการps faux | ใช้งาน อย่ากลัวที่จะยอมรับว่าเครื่องมือ XYZ ไม่เหมาะสมที่สุด
kevinf

10

โดยทั่วไป perl จะแทนที่ awk / sed / grep et al., และเป็นมากพกพามากขึ้น (เช่นเดียวกับเป็นเพียงมีดพับที่ดีกว่า)

perl -lane 'print "@F[8..$#F]"'

Timtowtdi ใช้แน่นอน


คุณต้องเพิ่มตัวเลือกบรรทัดคำสั่ง-lหรือเพิ่ม\nในคำสั่งพิมพ์
glenn jackman

@glenn jackman: เป็นไปได้. ไม่จำเป็นหากเป็นส่วนหนึ่งของข้อความอื่นหรือถูกกำหนดให้กับตัวแปรเป็นต้นเท่าที่ "ดีกว่า" ไป perl ก็ดูดีขึ้นอย่างแน่นอนในขนาดเล็ก สามารถดูรกมากในขนาดใหญ่เป็นที่ยอมรับ
bobbogo

อย่าเข้าใจฉันผิดฉันชอบ Perl ฉันชอบ awk สำหรับสิ่งที่เป็นอยู่
glenn jackman

อุปกรณ์ฝังตัวของฉันไม่ได้มาพร้อมกับ Perl แต่มี awk
Sepero

การลงคะแนนเนื่องจากคำถามถามว่าจะทำอย่างไรใน awk ไม่ใช่ perl, ruby, java, python, bash
Tom Harrison

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

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

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

fromField () { 
awk -v m="\x01" -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 = 0 จะส่งคืนทั้งบรรทัดตามที่เป็นอยู่และสำหรับ n> NF สตริงว่าง


นี่เป็นความคิดที่ดี มันใช้ไม่ได้กับ Mac ปัจจุบันที่ใช้ gawk ทั่วไปเพราะ $ 0 ยุบ การแก้ไขคือตั้งค่าตัวแปรเป็น $ 0 เป็นขั้นตอนแรกเช่น '{s = $ 0; ... print substr (s, index (s, m) +1}
joelparkerhenderson

1

นี่คือตัวอย่างของls -lผลลัพธ์:

-rwxr-----@ 1 ricky.john  1493847943   5610048 Apr 16 14:09 00-Welcome.mp4
-rwxr-----@ 1 ricky.john  1493847943  27862521 Apr 16 14:09 01-Hello World.mp4
-rwxr-----@ 1 ricky.john  1493847943  21262056 Apr 16 14:09 02-Typical Go Directory Structure.mp4
-rwxr-----@ 1 ricky.john  1493847943  10627144 Apr 16 14:09 03-Where to Get Help.mp4

วิธีการแก้ปัญหาของฉันที่จะโพสต์อะไรที่พิมพ์$9เป็นawk '{print substr($0, 61, 50)}'



0

ในการแสดง 3 ฟิลด์แรกและพิมพ์ฟิลด์ที่เหลือคุณสามารถใช้ได้:

awk '{s = ""; for (i=4; i<= NF; i++) s= s $i : "; print $1 $2 $3 s}' filename

โดยที่ $ 1 $ 2 $ 3 คือ 3 ช่องแรก


0
function print_fields(field_num1, field_num2){
    input_line = $0

    j = 1;
    for (i=field_num1; i <= field_num2; i++){
        $(j++) = $(i);

    }
    NF = field_num2 - field_num1 + 1;
    print $0

    $0 = input_line
}

0

การใช้ cut แทน awk และการเอาชนะปัญหาด้วยการหาคอลัมน์ที่จะเริ่มต้นโดยใช้คำสั่ง -c character cut

ที่นี่ฉันกำลังบอกว่าให้ฉันทั้งหมดยกเว้น 49 อักขระแรกของผลลัพธ์

 ls -l /some/path/*/* | cut -c 50-

/*/*/ในตอนท้ายของคำสั่งคำสั่ง ls ไม่ว่าจะเป็นการแสดงฉันสิ่งที่อยู่ในไดเรกทอรีย่อยเกินไป

คุณยังสามารถดึงอักขระบางช่วงออกมาได้อีกด้วย (จากหน้าคนตัด) เช่นแสดงชื่อและเวลาเข้าสู่ระบบของผู้ใช้ที่เข้าสู่ระบบในปัจจุบัน:

       who | cut -c 1-16,26-38
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.