ใช้คอลัมน์ที่ n ในไฟล์ข้อความ


85

ฉันมีไฟล์ข้อความ:

1 Q0 1657 1 19.6117 Exp
1 Q0 1410 2 18.8302 Exp
2 Q0 3078 1 18.6695 Exp
2 Q0 2434 2 14.0508 Exp
2 Q0 3129 3 13.5495 Exp

ฉันต้องการใช้คำที่ 2 และ 4 ของทุกบรรทัดดังนี้:

1657 19.6117
1410 18.8302
3078 18.6695
2434 14.0508
3129 13.5495

ฉันใช้รหัสนี้:

 nol=$(cat "/path/of/my/text" | wc -l)
 x=1
 while  [ $x -le "$nol" ]
 do
     line=($(sed -n "$x"p /path/of/my/text)
     echo ""${line[1]}" "${line[3]}""  >> out.txt
     x=$(( $x + 1 ))
 done

ใช้งานได้ แต่มีความซับซ้อนมากและใช้เวลานานในการประมวลผลไฟล์ข้อความยาว ๆ

มีวิธีที่ง่ายกว่านี้ไหม


1
คำที่ 2 ของทุกแถวเรียกว่าคอลัมน์ที่ 2 ง่ายๆ!
Bernard

คำตอบ:


127

iirc:

cat filename.txt | awk '{ print $2 $4 }'

หรือตามที่กล่าวไว้ในความคิดเห็น:

awk '{ print $2 $4 }' filename.txt

16
อู้วค !!! awk '{print $2,$4}' filename.txtดีกว่า (ไม่มีท่อเรียกโปรแกรมเดียว)
สีน้ำเงิน

5
@blue ฉันมักใช้catในสคริปต์ทุบตีของฉันแทนที่จะระบุชื่อไฟล์เนื่องจากค่าใช้จ่ายมีน้อยและเนื่องจากไวยากรณ์cat ... | ... > ...แสดงให้เห็นอย่างชัดเจนว่าอินพุตคืออะไรและเอาต์พุตไปที่ใด คุณพูดถูกแล้วที่นี่ไม่จำเป็นจริงๆ
Tom van der Woerdt

8
@ TomvanderWoerdt: บางครั้งฉันก็เขียน< input awk '{ print $2 $4 }' > outputเพื่อจุดประสงค์นั้น
ruakh

68

คุณสามารถใช้cutคำสั่ง:

cut -d' ' -f3,5 < datafile.txt

พิมพ์

1657 19.6117
1410 18.8302
3078 18.6695
2434 14.0508
3129 13.5495

ที่

  • -d' '- หมายถึงใช้spaceเป็นตัวคั่น
  • -f3,5 - พิมพ์และพิมพ์คอลัมน์ที่ 3 และ 5

cutเป็นได้เร็วขึ้นมากสำหรับไฟล์ขนาดใหญ่เป็นวิธีการแก้ปัญหาเปลือกที่บริสุทธิ์ หากไฟล์ของคุณถูกคั่นด้วยช่องว่างหลายช่องคุณสามารถลบออกก่อนเช่น:

sed 's/[\t ][\t ]*/ /g' < datafile.txt | cut -d' ' -f3,5

ที่ (GNU) sed จะเข้ามาแทนที่ใด ๆtabหรือตัวอักษรที่มีเพียงหนึ่งเดียวspacespace

สำหรับตัวแปร - นี่คือโซลูชัน perl ด้วย:

perl -lanE 'say "$F[2] $F[4]"' < datafile.txt

1
ใช้งานได้ดี ... ถ้าคุณรับประกันว่าจำนวนช่องว่างในแต่ละบรรทัดแน่นอน ... :)
rogerdpack

24

เพื่อความสมบูรณ์:

while read _ _ one _ two _; do
    echo "$one $two"
done < file.txt

แทน_ตัวแปรตามอำเภอใจ (เช่นjunk) สามารถใช้ได้เช่นกัน ประเด็นก็คือการแยกคอลัมน์

การสาธิต:

$ while read _ _ one _ two _; do echo "$one $two"; done < /tmp/file.txt
1657 19.6117
1410 18.8302
3078 18.6695
2434 14.0508
3129 13.5495

ดีอ่านได้และไม่ต้องใช้ perls / awks / อื่น ๆ ทั้งหมดในเปลือกเดียวโดย builtins
Petr Matousu

6

อีกหนึ่งตัวแปรง่ายๆ -

$ while read line
  do
      set $line          # assigns words in line to positional parameters
      echo "$3 $5"
  done < file

4

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

วิธีที่ดีที่สุดในการวนซ้ำบรรทัดของไฟล์คือการใช้การwhileวนซ้ำโดยมีคำสั่ง condition- readbuiltin:

while IFS= read -r line ; do
    # $line is a single line of the file, as a single string
    : ... commands that use $line ...
done < input_file.txt

ในกรณีของคุณเนื่องจากคุณต้องการแยกบรรทัดออกเป็นอาร์เรย์และreadbuiltin มีการสนับสนุนพิเศษสำหรับการเติมตัวแปรอาร์เรย์ซึ่งเป็นสิ่งที่คุณต้องการคุณสามารถเขียน:

while read -r -a line ; do
    echo ""${line[1]}" "${line[3]}"" >> out.txt
done < /path/of/my/text

หรือดีกว่า:

while read -r -a line ; do
    echo "${line[1]} ${line[3]}"
done < /path/of/my/text > out.txt

อย่างไรก็ตามสำหรับสิ่งที่คุณทำคุณสามารถใช้cutยูทิลิตี้:

cut -d' ' -f2,4 < /path/of/my/text > out.txt

(หรือawkตามที่ Tom van der Woerdt แนะนำหรือperlหรือแม้กระทั่งsed)


จะชอบreadมากกว่าcutเพราะมันเป็นที่แข็งแกร่งกับช่องว่างหลายระหว่างเขตและคุณไม่จำเป็นต้องมายากลอาร์เรย์:while read word1 word2 word3 word4 rest; do doSomethingWith $word2 $word4; done
user829755

3

หากคุณกำลังใช้ข้อมูลที่มีโครงสร้างสิ่งนี้มีประโยชน์เพิ่มเติมในการไม่เรียกใช้กระบวนการเชลล์เพิ่มเติมเพื่อเรียกใช้trและ / cutหรือบางสิ่ง ...

(แน่นอนคุณจะต้องป้องกันปัจจัยการผลิตที่ไม่ดีด้วยเงื่อนไขและทางเลือกที่ดี)

...
while read line ; 
do 
    lineCols=( $line ) ;
    echo "${lineCols[0]}"
    echo "${lineCols[1]}"
done < $myFQFileToRead ; 
...
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.