พิมพ์ทั้งหมดยกเว้นสามคอลัมน์แรก


112

ยุ่งยากเกินไป:

awk '{print " "$4" "$5" "$6" "$7" "$8" "$9" "$10" "$11" "$12" "$13}' things

43
มีเหตุผลอะไรที่คุณใช้cut -f3-ไม่ได้?
Cascabel

1
@hhh nice one .. ฉันชอบความคิดของคำตอบแบบสรุป
Chris Seymour

2
@Jefromi - เนื่องจากมีปัญหาการบัฟเฟอร์บรรทัดกับการตัดซึ่ง awk ไม่มี: stackoverflow.com/questions/14360640/…
sdaau


@Jefromi - ยังcutไม่มี regexes ก่อน{}การดำเนินการและเป็นวิธีที่โง่เขลาด้วยตัวคั่นฟิลด์ (จำนวนช่องว่างตัวแปร?) และคุณต้องระบุด้วยตนเอง ฉันคิดว่า OP ต้องการได้ยินเกี่ยวกับshift Nคำสั่งบางอย่างซึ่งไม่มีอยู่ สิ่งที่ใกล้เคียงที่สุดคือ$1="";$2="";(...);print}แต่ในกรณีของฉันมันทิ้งช่องว่างนำหน้าไว้ (อาจเป็นตัวคั่น)
Tomasz Gandor

คำตอบ:


50

โซลูชันที่ไม่เพิ่มช่องว่างนำหน้าหรือต่อท้าย:

awk '{ for(i=4; i<NF; i++) printf "%s",$i OFS; if(NF) printf "%s",$NF; printf ORS}'

### Example ###
$ echo '1 2 3 4 5 6 7' |
  awk '{for(i=4;i<NF;i++)printf"%s",$i OFS;if(NF)printf"%s",$NF;printf ORS}' |
  tr ' ' '-'
4-5-6-7

Sudo_Oเสนอการปรับปรุงที่สวยงามโดยใช้ตัวดำเนินการที่เกี่ยวข้องNF?ORS:OFS

$ echo '1 2 3 4 5 6 7' |
  awk '{ for(i=4; i<=NF; i++) printf "%s",$i (i==NF?ORS:OFS) }' |
  tr ' ' '-'
4-5-6-7

EdMortonนำเสนอโซลูชันที่รักษาช่องว่างเดิมระหว่างฟิลด์:

$ echo '1   2 3 4   5    6 7' |
  awk '{ sub(/([^ ]+ +){3}/,"") }1' |
  tr ' ' '-'
4---5----6-7

BinaryZebraยังมีโซลูชันที่ยอดเยี่ยมอีกสองวิธี:
(โซลูชันเหล่านี้ยังรักษาช่องว่างต่อท้ายจากสตริงเดิม)

$ echo -e ' 1   2\t \t3     4   5   6 7 \t 8\t ' |
  awk -v n=3 '{ for ( i=1; i<=n; i++) { sub("^["FS"]*[^"FS"]+["FS"]+","",$0);} } 1 ' |
  sed 's/ /./g;s/\t/->/g;s/^/"/;s/$/"/'
"4...5...6.7.->.8->."

$ echo -e ' 1   2\t \t3     4   5   6 7 \t 8\t ' |
  awk -v n=3 '{ print gensub("["FS"]*([^"FS"]+["FS"]+){"n"}","",1); }' |
  sed 's/ /./g;s/\t/->/g;s/^/"/;s/$/"/'
"4...5...6.7.->.8->."

วิธีแก้ปัญหาที่ได้รับจากlarsrในความคิดเห็นนั้นเกือบถูกต้อง:

$ echo '1 2 3 4 5 6 7' | 
  awk '{for (i=3;i<=NF;i++) $(i-2)=$i; NF=NF-2; print $0}' | tr  ' ' '-'
3-4-5-6-7

นี่คือโซลูชันlarsrเวอร์ชันคงที่และเป็นพารามิเตอร์:

$ echo '1 2 3 4 5 6 7' | 
  awk '{for(i=n;i<=NF;i++)$(i-(n-1))=$i;NF=NF-(n-1);print $0}' n=4 | tr ' ' '-'
4-5-6-7

คำตอบอื่น ๆ ทั้งหมดก่อน ก.ย. 2556 นั้นดี แต่เพิ่มช่องว่าง:


คำตอบของ EdMorton ไม่ได้ผลสำหรับฉัน (bash 4.1.2 (1) -release, GNU Awk 3.1.7 หรือ bash 3.2.25 (1) -release, GNU Awk 3.1.5) แต่พบอีกวิธีหนึ่งที่นี่ :echo ' This is a test' | awk '{print substr($0, index($0,$3))}'
elysch

1
ไม่ @elysch ซึ่งจะใช้ไม่ได้โดยทั่วไปดูเหมือนว่าจะทำงานได้เมื่อมีค่าอินพุตเฉพาะบางอย่าง ดูความคิดเห็นที่ฉันเพิ่มไว้ด้านล่างความคิดเห็นของคุณใต้คำตอบของฉัน
Ed Morton

1
สวัสดี @fedorqui คำตอบของฉันคือคำตอบแรก ในคำตอบเดิมของฉันฉันกำลังอธิบายว่าทำไมคำตอบอื่นจึงไม่ถูกต้อง (ช่องว่างนำหน้าหรือต่อท้ายเพิ่มเติม) บางคนเสนอการปรับปรุงภายในความคิดเห็น เราได้ขอให้ OP เลือกคำตอบที่ถูกต้องมากขึ้นและเขา / เธอได้เลือกของฉันแล้ว หลังจากผู้ร่วมให้ข้อมูลรายอื่นแก้ไขคำตอบของฉันเพื่ออ้างอิงคำตอบนั้น (ดูประวัติ) ชัดเจนสำหรับคุณหรือไม่? คุณแนะนำอะไรให้ฉันปรับปรุงความเข้าใจคำตอบของฉัน ไชโย ;-)
olibre

1
คุณพูดถูกต้องและฉันเสียใจมากที่เข้าใจผิด ฉันอ่านคำตอบอย่างรวดเร็วและไม่สังเกตเห็นคำตอบเดิมของคุณ (ใช่ฉันอ่านเร็วเกินไป) +1 สำหรับคำตอบโดยใช้เคล็ดลับที่ดีในการวนซ้ำถึง NF-1 จากนั้นพิมพ์องค์ประกอบสุดท้ายเพื่อหลีกเลี่ยงการเว้นวรรคเพิ่มเติม และขอโทษอีกครั้ง! (จะลบความคิดเห็นของฉันในหนึ่งวันหรือมากกว่านั้นเพื่อป้องกันความเข้าใจผิดจากผู้อ่านในอนาคต)
fedorqui 'SO หยุดทำร้าย'

1
ฉันจะใช้ส่วนหัวบางประเภท: <คำตอบของคุณ> จากนั้นกฎแนวนอนตามด้วยชื่อเรื่องใหญ่ "การเปรียบเทียบคำตอบอื่น ๆ " มิฉะนั้นให้ย้ายการเปรียบเทียบนี้ไปยังคำตอบอื่นเนื่องจากเห็นได้ชัดว่าผู้คนมักจะชอบคำตอบสั้น ๆ ในวิสัยทัศน์ "gimme my code"
:)

75
awk '{for(i=1;i<4;i++) $i="";print}' file

4
สิ่งนี้จะปล่อยให้OFSเป็นผู้นำในขณะที่คุณไม่ได้จัดการกับNFพื้นที่ชั้นนำในระเบียน
Chris Seymour

70

ใช้ตัด

$ cut -f4-13 file

หรือหากคุณยืนยันที่ awk และ $ 13 คือช่องสุดท้าย

$ awk '{$1=$2=$3="";print}' file

อื่น

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

14
น่าจะดีกว่าที่จะใช้ "NF" มากกว่า "13" ในตัวอย่างสุดท้าย
glenn jackman

2
2 สถานการณ์ที่ขึ้นอยู่กับ OP ในการตัดสินใจ ถ้า 13 เป็นฟิลด์สุดท้ายการใช้ NF ก็ไม่เป็นไร ถ้าไม่ใช้ 13 ก็เหมาะสม
ghostdog74

3
2nd ต้องลบสำเนา OFS 3 ชุดตั้งแต่เริ่มต้นที่ $ 0 อันดับ 3 จะดีกว่าprintf "%s ",$iเนื่องจากคุณไม่รู้ว่า$iอาจมี%sหรือคล้ายกัน แต่นั่นจะเป็นการพิมพ์ช่องว่างส่วนท้าย
พิรุธจิม

38

ลองสิ่งนี้:

awk '{ $1=""; $2=""; $3=""; print $0 }'

1
นี่เป็นสิ่งที่ดีเนื่องจากความไดนามิกเป็นอย่างไร คุณสามารถเพิ่มคอลัมน์ในตอนท้ายและไม่ต้องเขียนสคริปต์ของคุณใหม่
MinceMan

1
นี่แสดงให้เห็นถึงปัญหาที่แท้จริงที่คำถามพยายามจัดการกับคุณเพียงแค่ทำในสิ่งที่ตรงกันข้าม แล้วพิมพ์จากฟิลด์ที่ 100 ล่ะ? หมายเหตุพูดถึงคุณไม่จัดการกับเพื่อให้คุณออกจากชั้นนำNF OFS
Chris Seymour

24

วิธีที่ถูกต้องในการทำเช่นนี้คือการใช้ช่วงเวลา RE เพราะช่วยให้คุณระบุจำนวนฟิลด์ที่จะข้ามและรักษาระยะห่างระหว่างฟิลด์สำหรับฟิลด์ที่เหลือ

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

$ echo '1   2 3 4   5    6' |
awk '{sub(/([^ ]+ +){3}/,"")}1'
4   5    6

หากคุณต้องการรองรับช่องว่างนำหน้าและช่องว่างที่ไม่ใช่ช่องว่าง แต่ใช้ FS เริ่มต้นอีกครั้งนั่นคือ:

$ echo '  1   2 3 4   5    6' |
awk '{sub(/[[:space:]]*([^[:space:]]+[[:space:]]+){3}/,"")}1'
4   5    6

หากคุณมี FS ที่เป็น RE คุณไม่สามารถลบล้างในชุดอักขระได้คุณสามารถแปลงเป็นอักขระเดียวก่อนได้ (RS เหมาะอย่างยิ่งหากเป็นอักขระเดี่ยวเนื่องจาก RS CANNOT ไม่ปรากฏในฟิลด์มิฉะนั้นให้พิจารณา SUBSEP) จากนั้นใช้การทดแทนช่วงเวลา RE จากนั้นแปลงเป็น OFS เช่นถ้าโซ่ของ "." แยกฟิลด์:

$ echo '1...2.3.4...5....6' |
awk -F'[.]+' '{gsub(FS,RS);sub("([^"RS"]+["RS"]+){3}","");gsub(RS,OFS)}1'
4 5 6

เห็นได้ชัดว่าถ้า OFS เป็นอักขระเดี่ยวและไม่สามารถปรากฏในช่องป้อนข้อมูลคุณสามารถลดเป็น:

$ echo '1...2.3.4...5....6' |
awk -F'[.]+' '{gsub(FS,OFS); sub("([^"OFS"]+["OFS"]+){3}","")}1'
4 5 6

จากนั้นคุณมีปัญหาเดียวกันกับโซลูชันแบบวนซ้ำทั้งหมดที่กำหนดฟิลด์ใหม่ - FS จะถูกแปลงเป็น OFS หากเป็นปัญหาคุณต้องตรวจสอบฟังก์ชัน patsplit () ของ GNU awks


ไม่ได้ผลสำหรับฉัน (bash 4.1.2 (1) -release, GNU Awk 3.1.7 หรือ bash 3.2.25 (1) -release, GNU Awk 3.1.5) แต่พบอีกวิธีหนึ่งที่นี่ :echo ' This is a test' | awk '{print substr($0, index($0,$3))}'
elysch

2
ไม่จะล้มเหลวหาก $ 1 หรือ $ 2 มีสตริงที่ $ 3 ตั้งค่าไว้ ตัวอย่างเช่นลองแล้วecho ' That is a test' | awk '{print substr($0, index($0,$3))}'คุณจะพบว่าaนั่นคือ $ 3 ตรงกับaด้านThatในใน $ 1 ใน gawk เวอร์ชันเก่ามากเช่นคุณต้องเปิดใช้งานช่วงเวลา RE ด้วยแฟล็--re-interval
Ed Morton

2
คุณพูดถูกไม่ได้สังเกตเห็น ขอขอบคุณสำหรับความคิดเห็นของคุณ หลายครั้งต้องการใช้นิพจน์ทั่วไปกับ "{}" เพื่อระบุจำนวนองค์ประกอบและไม่เคยเห็น "--re-interval" ในผู้ชาย +1 สำหรับคุณ
elysch

1
1เป็นเงื่อนไขที่แท้จริงดังนั้นจึงเรียกใช้การกระทำ awk เริ่มต้นของการพิมพ์เรกคอร์ดปัจจุบัน
Ed Morton

1
idk เป็นอย่างไร แต่ฉันได้เพิ่มคำตอบแล้ว
Ed Morton

10

คำตอบทั้งหมดในปัจจุบันเพิ่มช่องว่างนำหน้าช่องว่างต่อท้ายหรือปัญหาตัวคั่นอื่น ๆ หากต้องการเลือกจากฟิลด์ที่สี่ที่ตัวคั่นเป็นช่องว่างและตัวคั่นเอาต์พุตเป็นช่องว่างเดียวโดยใช้awk :

awk '{for(i=4;i<=NF;i++)printf "%s",$i (i==NF?ORS:OFS)}' file

หากต้องการพารามิเตอร์สนามเริ่มต้นคุณสามารถทำได้:

awk '{for(i=n;i<=NF;i++)printf "%s",$i (i==NF?ORS:OFS)}' n=4 file

และฟิลด์สิ้นสุด:

awk '{for(i=n;i<=m=(m>NF?NF:m);i++)printf "%s",$i (i==m?ORS:OFS)}' n=4 m=10 file

6
awk '{$1=$2=$3="";$0=$0;$1=$1}1'

อินพุต

1 2 3 4 5 6 7

เอาท์พุต

4 5 6 7

4
echo 1 2 3 4 5| awk '{ for (i=3; i<=NF; i++) print $i }'

3
หรือหากต้องการให้อยู่ในบรรทัดเดียวกันให้กำหนด $ 3 ถึง $ 1 เป็นต้นจากนั้นเปลี่ยน NF เป็นจำนวนฟิลด์ที่ถูกต้อง echo 1 2 3 4 5| awk '{ for (i=3; i<=NF; i++) $(i-2)=$i; NF=NF-2; print $0 }'
larsr

สวัสดี @larsr. บรรทัดคำสั่งที่คุณเสนอคือคำตอบเดียวที่ถูกต้อง คำตอบอื่น ๆ ทั้งหมดจะเพิ่มช่องว่าง (นำหน้าหรือต่อท้าย) กรุณาโพสต์บรรทัดคำสั่งของคุณในคำตอบใหม่ฉันจะโหวตให้ ;-)
olibre

1
สวัสดี @sudo_O ฉันกำลังพูดกับ @larsr เกี่ยวกับบรรทัดคำสั่งที่เขาเสนอในความคิดเห็นของเขา ฉันใช้เวลาประมาณห้านาทีก่อนที่จะหา quiproco (เข้าใจผิด) ฉันเห็นด้วยคำตอบ @Vetsin แทรกบรรทัดใหม่ ( ORS) ระหว่างฟิลด์ ไชโยสำหรับความคิดริเริ่มของคุณ (ฉันชอบคำตอบของคุณ) ไชโย
olibre

3

อีกวิธีหนึ่งในการหลีกเลี่ยงการใช้คำสั่งพิมพ์:

 $ awk '{$1=$2=$3=""}sub("^"FS"*","")' file

ใน awk เมื่อเงื่อนไขเป็น true print เป็นการกระทำเริ่มต้น


นี่มีปัญหาทั้งหมด @lhf มีคำตอบ .. มันสั้นกว่านี้
Chris Seymour

ความคิดที่ดีมาก;) ดีกว่าคำตอบของฉัน! (ฉันได้โหวตคำตอบของคุณไปแล้วเมื่อปีที่แล้ว) ไชโย
olibre

ควรจะเป็น: awk '{$1=$2=$3=""}sub("^"OFS"+","")' fileเช่นเดียวกับ OFS สิ่งที่เหลืออยู่หลังจากเปลี่ยนเนื้อหา $ 1, $ 2 และ $ 3

3

ฉันไม่อยากเชื่อเลยว่าไม่มีใครเสนอเปลือกธรรมดา:

while read -r a b c d; do echo "$d"; done < file

+1 สำหรับโซลูชันที่คล้ายกัน ... แต่อาจมีปัญหาด้านประสิทธิภาพหากfileมีขนาดใหญ่ (> 10-30KiB) สำหรับไฟล์ขนาดใหญ่awkโซลูชันจะทำงานได้ดีกว่า
TrueY

3

ตัวเลือก 1 ถึง 3 มีปัญหาเกี่ยวกับช่องว่างหลายช่อง (แต่ทำได้ง่าย) นั่นคือเหตุผลในการพัฒนาตัวเลือก 4 และ 5 ซึ่งประมวลผลช่องว่างสีขาวหลายช่องโดยไม่มีปัญหา แน่นอนว่าหากใช้ตัวเลือก 4 หรือ 5 กับn=0ทั้งสองจะคงช่องว่างที่นำหน้าไว้เป็นn=0ไม่มีการแยก

ตัวเลือกที่ 1

วิธีการตัดอย่างง่าย (ใช้ได้กับตัวคั่นเดี่ยว):

$ echo '1 2 3 4 5 6 7 8' | cut -d' ' -f4-
4 5 6 7 8

ทางเลือกที่ 2

การบังคับให้คำนวณใหม่ awk บางครั้งแก้ปัญหาได้ (ใช้ได้กับ awk บางเวอร์ชัน) ของช่องว่างชั้นนำที่เพิ่ม:

$ echo '1 2 3 4 5 6 7 8' | awk '{ $1=$2=$3="";$0=$0;} NF=NF'
4 5 6 7 8

ตัวเลือก 3

การพิมพ์แต่ละฟิลด์ที่มีรูปแบบprintfจะให้การควบคุมมากขึ้น:

$ echo '    1    2  3     4   5   6 7     8  ' |
  awk -v n=3 '{ for (i=n+1; i<=NF; i++){printf("%s%s",$i,i==NF?RS:OFS);} }'
4 5 6 7 8

อย่างไรก็ตามคำตอบก่อนหน้านี้ทั้งหมดเปลี่ยน FS ทั้งหมดระหว่างฟิลด์เป็น OFS ลองสร้างวิธีแก้ปัญหาสองสามข้อ

ทางเลือกที่ 4

ลูปที่มี sub เพื่อลบฟิลด์และตัวคั่นนั้นพกพาได้มากกว่าและไม่ทำให้เกิดการเปลี่ยนแปลง FS เป็น OFS:

$ echo '    1    2  3     4   5   6 7     8  ' |
awk -v n=3 '{ for(i=1;i<=n;i++) { sub("^["FS"]*[^"FS"]+["FS"]+","",$0);} } 1 '
4   5   6 7     8

บันทึก: "^ [" FS "] *" คือการยอมรับอินพุตที่มีช่องว่างนำหน้า

ทางเลือกที่ 5

ค่อนข้างเป็นไปได้ที่จะสร้างโซลูชันที่ไม่เพิ่มช่องว่างที่นำหน้าหรือต่อท้ายและรักษาช่องว่างที่มีอยู่โดยใช้ฟังก์ชันgensubจาก GNU awk ดังนี้:

$ echo '    1    2  3     4   5   6 7     8  ' |
awk -v n=3 '{ print gensub("["FS"]*([^"FS"]+["FS"]+){"n"}","",1); }'
4   5   6 7     8 

นอกจากนี้ยังอาจใช้เพื่อสลับรายการเขตข้อมูลที่ได้รับการนับn:

$ echo '    1    2  3     4   5   6 7     8  ' |
  awk -v n=3 '{ a=gensub("["FS"]*([^"FS"]+["FS"]+){"n"}","",1);
                b=gensub("^(.*)("a")","\\1",1);
                print "|"a"|","!"b"!";
               }'
|4   5   6 7     8  | !    1    2  3     !

แน่นอนในกรณีเช่นนี้ OFS จะใช้เพื่อแยกทั้งสองส่วนของบรรทัดและยังคงพิมพ์ช่องว่างด้านหลังของฟิลด์

Note1: ["FS"]*ใช้เพื่อให้ช่องว่างนำหน้าในบรรทัดอินพุต


สวัสดี BZ คำตอบของคุณดี แต่ตัวเลือกที่ 3 ใช้ไม่ได้กับสตริงที่ขึ้นต้นด้วยช่องว่าง (เช่น" 1 2 3 4 5 6 7 8 ") ตัวเลือกที่ 4 นั้นดี แต่เว้นวรรคนำโดยใช้สตริงที่ขึ้นต้นด้วยช่องว่าง คุณคิดว่าสิ่งนี้แก้ไขได้หรือไม่? คุณสามารถใช้คำสั่งecho " 1 2 3 4 5 6 7 8 " | your awk script | sed 's/ /./g;s/\t/->/g;s/^/"/;s/$/"/'เพื่อตรวจสอบช่องว่างนำหน้า / กลาง / ท้าย ... ไชโย;)
olibre

สวัสดี @olibre การที่ตัวเลือก 3 ล้มเหลวด้วยช่องว่างสีขาวเป็นเหตุผลในการพัฒนาตัวเลือก 4 และ 5 ตัวเลือกที่ 4 จะเว้นช่องว่างนำหน้าหากอินพุตมีและ n ถูกตั้งค่าเป็น 0 (n = 0) ฉันเชื่อว่าเป็นคำตอบที่ถูกต้องเมื่อไม่มีการเลือกฟิลด์ (ไม่มีอะไรต้องแก้ไข IMO) ไชโย

เอาล่ะ. ขอบคุณสำหรับข้อมูลเพิ่มเติม :-) โปรดปรับปรุงคำตอบของคุณโดยให้ข้อมูลเพิ่มเติมเหล่านี้ :-) ไชโย
olibre

สมบูรณ์แบบ :-) ช่างน่าเสียดายที่ผู้ใช้ของคุณถูกปิดใช้งาน :-(
olibre

1

Cut มีแฟล็ก --complement ที่ทำให้ง่าย (และรวดเร็ว) ในการลบคอลัมน์ ไวยากรณ์ที่ได้นั้นคล้ายคลึงกับสิ่งที่คุณต้องการทำ - ทำให้โซลูชันอ่าน / ทำความเข้าใจได้ง่ายขึ้น การเติมเต็มยังใช้ได้กับกรณีที่คุณต้องการลบคอลัมน์ที่ไม่ติดกัน

$ foo='1 2 3 %s 5 6 7'
$ echo "$foo" | cut --complement -d' ' -f1-3
%s 5 6 7
$

คุณช่วยอธิบายคำตอบของคุณเพิ่มเติมได้ไหม
Zulu

การแก้ไขข้างต้นช่วยในการทำความเข้าใจหรือไม่? ประเด็นคือการใช้ธงเสริมของการตัด โซลูชันควรจะใช้งานได้รวดเร็วและรัดกุมกว่าโซลูชันที่ใช้ AWK หรือ perl นอกจากนี้ยังสามารถตัดคอลัมน์โดยพลการ
Michael Back

1

โซลูชัน Perl ที่ไม่เพิ่มช่องว่างนำหน้าหรือต่อท้าย:

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

@Fอาร์เรย์perl autosplit เริ่มต้นที่ดัชนี0ในขณะที่ฟิลด์ awk เริ่มต้นด้วย$1


โซลูชัน Perl สำหรับข้อมูลที่คั่นด้วยจุลภาค:

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

โซลูชัน Python:

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


0

สำหรับฉันโซลูชันที่กะทัดรัดและสอดคล้องกับคำขอมากที่สุดคือ

$ a='1   2\t \t3     4   5   6 7 \t 8\t '; 
$ echo -e "$a" | awk -v n=3 '{while (i<n) {i++; sub($1 FS"*", "")}; print $0}'

และหากคุณมีบรรทัดเพิ่มเติมในการประมวลผลเช่นไฟล์อินสแตนซ์foo.txtอย่าลืมรีเซ็ต i เป็น 0:

$ awk -v n=3 '{i=0; while (i<n) {i++; sub($1 FS"*", "")}; print $0}' foo.txt

ขอบคุณฟอรัมของคุณ


0

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

ฉันมีบันทึกที่หลังจาก $ 5 พร้อมที่อยู่ IP สามารถเป็นข้อความเพิ่มเติมหรือไม่มีข้อความก็ได้ ฉันต้องการทุกอย่างตั้งแต่ที่อยู่ IP ไปจนถึงท้ายบรรทัดหากมีอะไรหลังจาก $ 5 ในกรณีของฉันนี่เป็นจริงด้วยโปรแกรม awk ไม่ใช่ awk oneliner ดังนั้น awk ต้องแก้ปัญหา เมื่อฉันพยายามลบ 4 ช่องแรกโดยใช้คำตอบที่ดูดีและมีการโหวตมากที่สุด แต่ไม่ถูกต้อง:

echo "  7 27.10.16. Thu 11:57:18 37.244.182.218 one two three" | awk '{$1=$2=$3=$4=""; printf "[%s]\n", $0}'

มันพ่นคำตอบที่ผิดและไร้ประโยชน์ออกมา (ฉันเพิ่ม [] เพื่อแสดงให้เห็น):

[    37.244.182.218 one two three]

หากคอลัมน์มีความกว้างคงที่จนกว่าจะถึงจุดตัดและ awk คำตอบที่ถูกต้องและค่อนข้างง่ายคือ:

echo "  7 27.10.16. Thu 11:57:18 37.244.182.218 one two three" | awk '{printf "[%s]\n", substr($0,28)}'

ซึ่งสร้างผลลัพธ์ที่ต้องการ:

[37.244.182.218 one two three]

0

ฉันพบความเป็นไปได้อื่น ๆ แล้วบางทีมันอาจมีประโยชน์ด้วย ...

awk 'BEGIN {OFS=ORS="\t" }; {for(i=1; i<14; i++) print $i " "; print $NF "\n" }' your_file

หมายเหตุ: 1. สำหรับข้อมูลแบบตารางและจากคอลัมน์ $ 1 ถึง $ 14


0

ใช้ตัด:

cut -d <The character between characters> -f <number of first column>,<number of last column> <file name>

เช่น: หากคุณมีfile1:car.is.nice.equal.bmw

Run: cut -d . -f1,3 file1 จะพิมพ์car.is.nice


ดูเหมือนว่าโซลูชันของคุณอาจล้าหลัง โปรดตรวจสอบชื่อคำถามพิมพ์ทั้งหมด * แต่ * สามคอลัมน์แรก
Stefan Crain

-1

นี่ไม่ไกลจากคำตอบก่อนหน้านี้มากนัก แต่ช่วยแก้ปัญหาสองสามข้อ:

cols.sh:

#!/bin/bash
awk -v s=$1 '{for(i=s; i<=NF;i++) printf "%-5s", $i; print "" }'

ซึ่งตอนนี้คุณสามารถเรียกด้วยอาร์กิวเมนต์ที่จะเป็นคอลัมน์เริ่มต้น:

$ echo "1 2 3 4 5 6 7 8 9 10 11 12 13 14" | ./cols.sh 3 
3    4    5    6    7    8    9    10   11   12   13   14

หรือ:

$ echo "1 2 3 4 5 6 7 8 9 10 11 12 13 14" | ./cols.sh 7 
7    8    9    10   11   12   13   14

นี่คือ 1- ดัชนี; หากคุณต้องการจัดทำดัชนีเป็นศูนย์ให้ใช้i=s + 1แทน

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

#!/bin/bash
awk -v s=$1 -v e=$2 '{for(i=s; i<=e;i++) printf "%-5s", $i; print "" }'

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

$ echo "1 2 3 4 5 6 7 8 9 10 11 12 13 14" | ./cols.sh 7 9 
7    8    9

%-5sสอดคล้องผลตามที่คอลัมน์ตัวอักษร 5 ตัวกว้าง; หากยังไม่เพียงพอให้เพิ่มจำนวนหรือใช้%s(โดยเว้นวรรค) แทนหากคุณไม่สนใจเรื่องการจัดแนว


-1

โซลูชันที่ใช้ AWK printf ที่หลีกเลี่ยงปัญหา% และมีความพิเศษตรงที่จะไม่ส่งคืนค่าใด ๆ (ไม่มีอักขระส่งคืน) หากมีคอลัมน์ที่จะพิมพ์น้อยกว่า 4 คอลัมน์:

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

การทดสอบ:

$ x='1 2 3 %s 4 5 6'
$ echo "$x" | awk 'NF > 3 { for(i=4; i<NF; i++) printf("%s ", $(i)); print $(i) }'
%s 4 5 6
$ x='1 2 3'
$ echo "$x" | awk 'NF > 3 { for(i=4; i<NF; i++) printf("%s ", $(i)); print $(i) }'
$ x='1 2 3 '
$ echo "$x" | awk 'NF > 3 { for(i=4; i<NF; i++) printf("%s ", $(i)); print $(i) }'
$
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.