การใช้ awk เพื่อพิมพ์คอลัมน์ทั้งหมดจาก nth ถึงล่าสุด


310

บรรทัดนี้ใช้ได้จนกระทั่งฉันมีพื้นที่ว่างในฟิลด์ที่สอง

svn status | grep '\!' | gawk '{print $2;}' > removedProjs

มีวิธีที่จะพิมพ์ awk ทุกอย่างในราคา $ 2 หรือมากกว่าหรือไม่? ($ 3, $ 4 .. จนกว่าเราจะไม่มีคอลัมน์อีกต่อไป?)

ฉันคิดว่าฉันควรจะเพิ่มว่าฉันกำลังทำสิ่งนี้ในสภาพแวดล้อม Windows ด้วย Cygwin


11
นอกเหนือจากgrep | awkนี้ก็คือ Antipattern - คุณต้องการawk '/!/ { print $2 }'
tripleee

3
Unix "cut" ง่ายกว่า ...svn status | grep '\!' | cut -d' ' -f2- > removedProjs
roblogic

สำเนาซ้ำที่เป็นไปได้ของส่วนที่เหลือของฟิลด์พิมพ์ใน awk
acm

@tripleee: ฉันดีใจที่คุณพูดถึงเรื่องนี้ - ฉันผิดหวังที่เห็นมันทุกที่!
Graham Nicholls

คำตอบ:


489

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

awk '{$1=""; print $0}' somefile

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

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

93
gotcha: ออกจากพื้นที่ชั้นนำที่ห้อยอยู่กับ :(
raphinesse

5
ฉันชอบแนวทางปฏิบัติ ไม่จำเป็นต้องใช้ cat เพียงแค่ใส่ชื่อไฟล์หลังจากคำสั่ง awk
kon

45
@raphinesse คุณสามารถแก้ไขได้ด้วยawk '{$1=""; print substr($0,2)}' input_filename > output_filename
themiurgo

6
สิ่งนี้ใช้ไม่ได้กับตัวคั่นที่ไม่ใช่ช่องว่างแทนที่ด้วยช่องว่าง
Dejan

3
สำหรับตัวคั่นที่ไม่ใช่ช่องว่างคุณสามารถระบุตัวคั่นฟิลด์เอาต์พุต (OFS) เช่นเครื่องหมายจุลภาค: awk -F, -vOFS=, '{$1=""; print $0}'คุณจะสิ้นสุดด้วยตัวคั่นเริ่มต้น ( $1ยังคงรวมอยู่เช่นเดียวกับสตริงว่างเปล่า) คุณสามารถตัดสิ่งนั้นด้วยsed:awk -F, -vOFS=, '{$1=""; print $0}' | sed 's/^,//'
cherdt

99

มีคำถามซ้ำซ้อนกับคำตอบที่ง่ายกว่าโดยใช้การตัด:

 svn status |  grep '\!' | cut -d\  -f2-

-dระบุ delimeter (เว้นวรรค) , -fระบุรายชื่อของคอลัมน์(ทั้งหมดเริ่มต้นด้วย 2)


นอกจากนี้คุณยังสามารถใช้ "-b" เพื่อระบุตำแหน่ง (จากตัวละคร Nth เป็นต้นไป)
Dakatine

โปรดทราบว่าแม้ว่าสิ่งนี้จะทำงานเช่นเดียวกับawkเวอร์ชัน แต่ก็มีปัญหาการบัฟเฟอร์บรรทัดcutซึ่งawkไม่มี: stackoverflow.com/questions/14360640/…
sdaau

24
สวยและเรียบง่าย แต่มาพร้อมกับข้อแม้: awkปฏิบัติกับช่องว่างที่อยู่ติดกันหลายตัว เป็นตัวคั่นเดี่ยวในขณะที่cutไม่; ด้วย - แม้ว่านี่จะไม่ใช่ปัญหาในกรณีที่อยู่ในมือ - cutเพียงยอมรับตัวอักษรตัวเดียว ในฐานะที่เป็นตัวคั่นในขณะที่awkช่วยให้ regex
mklement0

ตามนี้: stackoverflow.com/a/39217130/8852408เป็นไปได้ว่าโซลูชันนี้ไม่มีประสิทธิภาพมาก
FcknGioconda

85

คุณสามารถใช้ for-loop เพื่อวนลูปผ่านการพิมพ์ฟิลด์ $ 2 ถึง $ NF (ตัวแปรบิวด์อินที่แสดงจำนวนฟิลด์ในบรรทัด)

แก้ไข: เนื่องจาก "พิมพ์" ต่อท้ายบรรทัดใหม่คุณจะต้องบัฟเฟอร์ผลลัพธ์:

awk '{out=""; for(i=2;i<=NF;i++){out=out" "$i}; print out}'

หรือใช้ printf:

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

ดังนั้นฉันจึงลองทำเช่นนี้ แต่คิดว่าฉันขาดอะไรบางอย่าง .. นี่คือสิ่งที่ฉันได้สถานะ svn | grep '\!' | gawk '{for (i = 1; i <= $ NF; i ++) พิมพ์ $ i "";;}'> removeProjs
Andy

เนื่องจากการพิมพ์ต่อท้ายบรรทัดใหม่คุณจะต้องการบัฟเฟอร์ผลลัพธ์ ดูการแก้ไขของฉัน
VeeArr

1
ฉันชอบคำตอบนี้ดีกว่าเพราะมันแสดงวิธีวนลูปผ่านฟิลด์ต่างๆ
Edward Falk

3
หากคุณต้องการพิมพ์เพื่อใช้ช่องว่างให้เปลี่ยนตัวคั่นระเบียนผลลัพธ์: awk '{ORS = ""; สำหรับ (i = 2; i <NF; i ++) พิมพ์ $ i} 'somefile
Christian Lescuyer

3
จะมีช่องว่างมากเกินไปเสมอ วิธีนี้ใช้ได้ผลดีกว่า: '{for(i=11;i<=NF-1;i++){printf "%s ", $i}; print $NF;}'ไม่มีช่องว่างนำหน้าหรือต่อท้าย
Marki

24
awk '{out=$2; for(i=3;i<=NF;i++){out=out" "$i}; print out}'

คำตอบของฉันขึ้นอยู่กับ VeeArrแต่ฉันสังเกตว่ามันเริ่มต้นด้วยพื้นที่สีขาวก่อนที่จะพิมพ์คอลัมน์ที่สอง (และส่วนที่เหลือ) เนื่องจากฉันมีเพียง 1 คะแนนชื่อเสียงฉันไม่สามารถแสดงความคิดเห็นได้ดังนั้นนี่จึงเป็นคำตอบใหม่:

เริ่มต้นด้วย "out" เป็นคอลัมน์ที่สองจากนั้นเพิ่มคอลัมน์อื่น ๆ ทั้งหมด (หากมี) สิ่งนี้จะดำเนินไปด้วยดีตราบใดที่มีคอลัมน์ที่สอง


2
ยอดเยี่ยมคุณลบตัวแปร $ ออกหน้าตัวแปรซึ่งมีความสำคัญเช่นกัน
Alexis Wilke

15

โซลูชันส่วนใหญ่ที่มี awk ออกจากพื้นที่ ตัวเลือกที่นี่หลีกเลี่ยงปัญหานั้น

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

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

command | cut -d' ' -f3-

ตัวเลือก 2

การบังคับให้ awk re-calc บางครั้งลบพื้นที่ว่างนำหน้า (OFS) ที่เหลือโดยการลบฟิลด์แรก (ทำงานกับ awk บางรุ่น):

command | awk '{ $1=$2="";$0=$0;} NF=NF'

ตัวเลือก 3

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

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

อย่างไรก็ตามคำตอบก่อนหน้านี้ทั้งหมดเปลี่ยน FS ที่ทำซ้ำทั้งหมดระหว่างเขตข้อมูลเป็น OFS ลองสร้างตัวเลือกสองสามอย่างที่ไม่ทำ

ตัวเลือก 4 (แนะนำ)

วนซ้ำพร้อมย่อยเพื่อลบฟิลด์และตัวคั่นที่ด้านหน้า
และการใช้ค่า FS แทนการเว้นวรรค (ซึ่งอาจมีการเปลี่ยนแปลงได้)
พกพาได้มากกว่าและไม่เปลี่ยน FS เป็น OFS: หมายเหตุ:สิ่ง^[FS]*นี้คือการยอมรับอินพุตด้วยช่องว่างนำหน้า

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

ตัวเลือก 5

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

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

นอกจากนี้ยังอาจใช้เพื่อสลับกลุ่มของฟิลด์ที่ให้นับn:

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

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

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


13

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

awk -F" " '{ for (i=4; i<=NF; i++) print $i }'
  1. โดยที่ -F "" กำหนดตัวคั่นสำหรับ awk ที่จะใช้ ในกรณีของฉันคือช่องว่างซึ่งเป็นตัวคั่นเริ่มต้นสำหรับ awk ซึ่งหมายความว่าสามารถละเว้น -F "" ได้

  2. ที่ NF กำหนดจำนวนฟิลด์ / คอลัมน์ทั้งหมด ดังนั้นการวนซ้ำจะเริ่มจากฟิลด์ที่ 4 จนถึงฟิลด์ / คอลัมน์สุดท้าย

  3. ที่ $ N ดึงค่าของฟิลด์ Nth ดังนั้นพิมพ์ $ i จะพิมพ์ฟิลด์ / คอลัมน์ปัจจุบันตามจำนวนการวนรอบ


4
ปัญหาที่พิมพ์แต่ละฟิลด์ในบรรทัดที่แตกต่างกัน
mveroone

ไม่มีอะไรหยุดคุณต่อท้ายนี้ในตอนท้าย :-) `| tr '\ n' '' `
koullislp

3
สายไปหน่อย แต่ awk '{สำหรับ (i = 5; i <= NF; i ++) {printf "% s", $ i}}'
plitter


7

สิ่งนี้ทำให้ฉันรำคาญใจมากฉันนั่งลงและเขียนโปรแกรมcutแยกวิเคราะห์สเปคของฟิลด์ที่เหมือนกันทดสอบกับ GNU Awk 3.1.7

ก่อนอื่นให้สร้างสคริปต์ไลบรารี Awk ใหม่ที่มีชื่อว่าpfcutเช่น

sudo nano /usr/share/awk/pfcut

จากนั้นวางสคริปต์ด้านล่างและบันทึก หลังจากนั้นการใช้งานจะเป็นอย่างไร:

$ echo "t1 t2 t3 t4 t5 t6 t7" | awk -f pfcut --source '/^/ { pfcut("-4"); }'
t1 t2 t3 t4

$ echo "t1 t2 t3 t4 t5 t6 t7" | awk -f pfcut --source '/^/ { pfcut("2-"); }'
t2 t3 t4 t5 t6 t7

$ echo "t1 t2 t3 t4 t5 t6 t7" | awk -f pfcut --source '/^/ { pfcut("-2,4,6-"); }'
t1 t2 t4 t6 t7

เพื่อหลีกเลี่ยงการพิมพ์ทั้งหมดฉันเดาว่าวิธีที่ดีที่สุดสามารถทำได้ (ดูมิฉะนั้นโหลดฟังก์ชั่นผู้ใช้โดยอัตโนมัติเมื่อเริ่มต้นด้วย awk? - Unix & Linux Stack Exchange ) เพิ่มนามแฝงเป็น~/.bashrc; เช่นกับ:

$ echo "alias awk-pfcut='awk -f pfcut --source'" >> ~/.bashrc
$ source ~/.bashrc     # refresh bash aliases

... จากนั้นคุณสามารถโทร:

$ echo "t1 t2 t3 t4 t5 t6 t7" | awk-pfcut '/^/ { pfcut("-2,4,6-"); }'
t1 t2 t4 t6 t7

นี่คือที่มาของpfcutสคริปต์:

# pfcut - print fields like cut
#
# sdaau, GNU GPL
# Nov, 2013

function spfcut(formatstring)
{
  # parse format string
  numsplitscomma = split(formatstring, fsa, ",");
  numspecparts = 0;
  split("", parts); # clear/initialize array (for e.g. `tail` piping into `awk`)
  for(i=1;i<=numsplitscomma;i++) {
    commapart=fsa[i];
    numsplitsminus = split(fsa[i], cpa, "-");
    # assume here a range is always just two parts: "a-b"
    # also assume user has already sorted the ranges
    #print numsplitsminus, cpa[1], cpa[2]; # debug
    if(numsplitsminus==2) {
     if ((cpa[1]) == "") cpa[1] = 1;
     if ((cpa[2]) == "") cpa[2] = NF;
     for(j=cpa[1];j<=cpa[2];j++) {
       parts[numspecparts++] = j;
     }
    } else parts[numspecparts++] = commapart;
  }
  n=asort(parts); outs="";
  for(i=1;i<=n;i++) {
    outs = outs sprintf("%s%s", $parts[i], (i==n)?"":OFS); 
    #print(i, parts[i]); # debug
  }
  return outs;
}

function pfcut(formatstring) {
  print spfcut(formatstring);
}

ดูเหมือนว่าคุณต้องการใช้cutไม่ใช่awk
roblogic

5

การพิมพ์คอลัมน์เริ่มต้นจาก # 2 (เอาต์พุตจะไม่มีช่องว่างต่อท้ายในตอนเริ่มต้น):

ls -l | awk '{sub(/[^ ]+ /, ""); print $0}'

1
ดีแม้ว่าคุณควรเพิ่ม+หลังช่องว่างเนื่องจากเขตข้อมูลอาจถูกคั่นด้วยช่องว่างมากกว่า 1 ช่องว่าง ( awkถือว่าเป็นช่องว่างที่อยู่ติดกันหลายช่องเป็นตัวคั่นเดียว) นอกจากนี้awkจะไม่สนใจช่องว่างนำดังนั้นคุณควรเริ่มต้น regex ^[ ]*ด้วย ด้วยช่องว่างเป็นตัวคั่นคุณสามารถสรุปวิธีแก้ปัญหา ตัวอย่างต่อไปนี้จะคืนค่าทุกอย่างจากฟิลด์ที่ 3: awk '{sub(/^[ ]*([^ ]+ +){2}/, ""); print $0}'มันจะมีเล่ห์เหลี่ยมกับตัวคั่นฟิลด์ที่กำหนดเอง
mklement0


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

อันนี้ใช้ awk เพื่อพิมพ์ทั้งหมดยกเว้นฟิลด์สุดท้าย


3

นี่คือสิ่งที่ฉันต้องการจากคำแนะนำทั้งหมด:

การพิมพ์จากคอลัมน์ที่ 6 ถึงคอลัมน์สุดท้าย

ls -lthr | awk '{out=$6; for(i=7;i<=NF;i++){out=out" "$i}; print out}'

หรือ

ls -lthr | awk '{ORS=" "; for(i=6;i<=NF;i++) print $i;print "\n"}'

2

หากคุณต้องการคอลัมน์เฉพาะที่พิมพ์ด้วย delimeter โดยพลการ:

awk '{print $3 "  " $4}'

col # 3 col # 4

awk '{print $3 "anything" $4}'

เทือกเขา # 3anythingcol # 4

ดังนั้นหากคุณมีช่องว่างในคอลัมน์มันจะเป็นสองคอลัมน์ แต่คุณสามารถเชื่อมต่อกับตัวคั่นใดก็ได้หรือไม่มีก็ได้


2

วิธีการแก้ปัญหา Perl:

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

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

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

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

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

  • -e รันรหัส Perl

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

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


โซลูชั่น Python:

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


1

หากคุณไม่ต้องการจัดรูปแบบส่วนที่คุณไม่ได้ตัดออกใหม่ทางออกที่ดีที่สุดที่ฉันคิดได้เขียนไว้ในคำตอบของฉันใน:

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

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

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

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 

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

ในกรณีเฉพาะของคุณ:

svn status | grep '\!' | fromField 2 > removedProjs

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

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

กรณีแรกจะล้มเหลวเฉพาะในไฟล์ / สตรีมที่มีหมายเลขถ่านเลขฐานสิบหกที่หายาก 1


0

สิ่งนี้จะได้ผลถ้าคุณใช้ Bash และคุณสามารถใช้ 'x' ได้มากเท่าที่องค์ประกอบที่คุณต้องการจะทิ้งและมันจะข้ามช่องว่างหลายช่องหากไม่ได้หลบหนี

while read x b; do echo "$b"; done < filename

0

Perl:

@m=`ls -ltr dir | grep ^d | awk '{print \$6,\$7,\$8,\$9}'`;
foreach $i (@m)
{
        print "$i\n";

}

1
นี้ไม่ได้ตอบคำถามซึ่ง generalises ความต้องการที่จะพิมพ์จากคอลัมน์ชับไปยังจุดสิ้นสุด
roaima

0

awkฟังก์ชันนี้คืนค่าสตริงย่อยของ$0ที่มีฟิลด์จากbeginถึงend:

function fields(begin, end,    b, e, p, i) {
    b = 0; e = 0; p = 0;
    for (i = 1; i <= NF; ++i) {
        if (begin == i) { b = p; }
        p += length($i);
        e = p;
        if (end == i) { break; }
        p += length(FS);
    }
    return substr($0, b + 1, e - b);
}

เพื่อให้ทุกอย่างเริ่มต้นจากสนามที่ 3:

tail = fields(3);

ในการรับส่วนของ$0ที่ครอบคลุมฟิลด์ 3 ถึง 5:

middle = fields(3, 5);

b, e, p, iไร้สาระในรายการพารามิเตอร์ฟังก์ชั่นเป็นเพียงawkวิธีการประกาศตัวแปรท้องถิ่น


0

ฉันต้องการที่จะขยายคำตอบที่เสนอไปยังสถานการณ์ที่มีการคั่นเขตข้อมูลด้วยช่องว่างหลายช่อง - สาเหตุที่ OP ไม่ได้ใช้cutฉันคิดว่า

ฉันรู้ว่า OP ถามเกี่ยวกับawkแต่sedวิธีการจะทำงานที่นี่ (ตัวอย่างเช่นการพิมพ์คอลัมน์จาก 5 ถึงล่าสุด):

  • วิธีการ sed บริสุทธิ์

    sed -r 's/^\s*(\S+\s+){4}//' somefile

    คำอธิบาย:

    • s/// ใช้วิธีมาตรฐานในการทดแทน
    • ^\s* ตรงกับช่องว่างต่อเนื่องใด ๆ ที่จุดเริ่มต้นของบรรทัด
    • \S+\s+ หมายถึงคอลัมน์ของข้อมูล (ตัวอักษรที่ไม่ใช่ช่องว่างตามด้วยตัวอักษรช่องว่าง)
    • (){4} หมายถึงรูปแบบซ้ำแล้วซ้ำอีก 4 ครั้ง
  • sed และตัด

    sed -r 's/^\s+//; s/\s+/\t/g' somefile | cut -f5-

    โดยเพียงแค่แทนที่ช่องว่างต่อเนื่องด้วยแท็บเดียว;

  • tr และ cut: trสามารถใช้เพื่อบีบอักขระต่อเนื่องด้วยตัว-sเลือก

    tr -s [:blank:] <somefile | cut -d' ' -f5-

-1

ตัวอย่าง Awk ดูซับซ้อนที่นี่นี่เป็นไวยากรณ์เปลือก Bash ง่าย ๆ :

command | while read -a cols; do echo ${cols[@]:1}; done

คอลัมน์ที่n1ของคุณอยู่ที่ไหนนับจาก 0


ตัวอย่าง

รับเนื้อหาของไฟล์นี้ ( in.txt):

c1
c1 c2
c1 c2 c3
c1 c2 c3 c4
c1 c2 c3 c4 c5

นี่คือผลลัพธ์:

$ while read -a cols; do echo ${cols[@]:1}; done < in.txt 

c2
c2 c3
c2 c3 c4
c2 c3 c4 c5

-1

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

echo -e "a  b  c  d\te\t\tf g" | \
  perl -ne 'my @f = split /\s+/, $_, 3; printf "first: %s second: %s rest: %s", @f;'

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

หากต้องการเปลี่ยนจำนวนคอลัมน์ที่ควรแตกไฟล์ให้แทนที่3ในตัวอย่างด้วย n + 1


-1
ls -la | awk '{o=$1" "$3; for (i=5; i<=NF; i++) o=o" "$i; print o }'

จากคำตอบนี้ไม่เลว แต่ระยะห่างธรรมชาติหมดไป
โปรดเปรียบเทียบกับสิ่งนี้:

ls -la | cut -d\  -f4-

จากนั้นคุณจะเห็นความแตกต่าง

แม้ว่าls -la | awk '{$1=$2=""; print}'จะขึ้นอยู่กับคำตอบที่ได้รับการโหวตดีที่สุดจนถึงขณะนี้ยังไม่ได้จัดรูปแบบ

ดังนั้นฉันจะใช้ต่อไปนี้และยังอนุญาตคอลัมน์เลือกอย่างชัดเจนในการเริ่มต้น:

ls -la | cut -d\  -f1,4-

โปรดทราบว่าทุกพื้นที่มีการนับคอลัมน์ด้วยเช่นในคอลัมน์ด้านล่างคอลัมน์ 1 และ 3 นั้นว่างเปล่า 2 คือ INFO และ 4 คือ:

$ echo " INFO  2014-10-11 10:16:19  main " | cut -d\  -f1,3

$ echo " INFO  2014-10-11 10:16:19  main " | cut -d\  -f2,4
INFO 2014-10-11
$

-1

หากคุณต้องการจัดรูปแบบข้อความเชื่อมโยงคำสั่งของคุณด้วย echo และใช้ $ 0 เพื่อพิมพ์ฟิลด์สุดท้าย

ตัวอย่าง:

for i in {8..11}; do
   s1="$i"
   s2="str$i"
   s3="str with spaces $i"
   echo -n "$s1 $s2" | awk '{printf "|%3d|%6s",$1,$2}'
   echo -en "$s3" | awk '{printf "|%-19s|\n", $0}'
done

พิมพ์:

|  8|  str8|str with spaces 8  |
|  9|  str9|str with spaces 9  |
| 10| str10|str with spaces 10 |
| 11| str11|str with spaces 11 |

-9

เพราะนักโหวตที่โหวตมากที่สุดผิด 340 คนฉันเสียชีวิตไป 5 นาที! มีใครลองคำตอบนี้ก่อนที่จะยกเลิกการโหวตนี้ ไม่เห็นด้วย ไร้ประโยชน์โดยสิ้นเชิง

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

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

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

[    37.244.182.218 one two three]

มีแม้กระทั่ง sugestions บางอย่างที่จะรวมสารตั้งต้นกับคำตอบที่ผิดนี้ เช่นเดียวกับโรคแทรกซ้อนที่มีการปรับปรุง

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

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

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

[37.244.182.218 one two three]
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.