เปลี่ยนลำดับของบรรทัดในไฟล์


11

ฉันพยายามเปลี่ยนลำดับของเส้นในรูปแบบเฉพาะ การทำงานกับไฟล์ที่มีหลายบรรทัด (เช่น 99 บรรทัด) สำหรับทุกสามบรรทัดฉันต้องการให้บรรทัดที่สองเป็นบรรทัดที่สามและบรรทัดที่สามจะเป็นบรรทัดที่สอง

ตัวอย่าง.

1- อินพุต:

gi_1234
My cat is blue.
I have a cat.
gi_5678
My dog is orange.
I also have a dog.
...

2- เอาท์พุท:

gi_1234
I have a cat.
My cat is blue.
gi_5678
I also have a dog.
My dog is orange.
...

คำตอบ:


12

การใช้awkและเลขจำนวนเต็ม:

awk 'NR%3 == 1 { print } NR%3 == 2 { delay=$0 } NR%3 == 0 { print; print delay; delay=""} END { if(length(delay) != 0 ) { print delay } }' /path/to/input

ตัวดำเนินการโมดูลัสดำเนินการหารจำนวนเต็มและส่งคืนส่วนที่เหลือดังนั้นสำหรับแต่ละบรรทัดมันจะส่งคืนลำดับ 1, 2, 0, 1, 2, 0 [... ] เมื่อรู้ว่าเราเพิ่งบันทึกอินพุตบนบรรทัดที่โมดูลัสเป็น 2 ในภายหลัง - เพื่อปัญญาหลังจากพิมพ์อินพุตเมื่อมันเป็นศูนย์


เรามีข้อบกพร่องเล็ก ๆ ที่นี่ ดูคำตอบส่วนปรับปรุงเล็กน้อยของฉัน
Sergiy Kolodyazhnyy

ขอบคุณสำหรับการจับที่ดี NR%3 == 0 { print; print delay; delay=""} END { if(length(delay) != 0 ) { print delay }ผมได้รวมการแก้ไขลงในคำตอบของฉันในรูปแบบของ
DopeGhoti

23
$ seq 9 | sed -n 'p;n;h;n;G;p'
1
3
2
4
6
5
7
9
8

นั่นคือprint บรรทัดปัจจุบันรับnext หนึ่งhเก่ารับnext หนึ่งGและบรรทัดที่จัดขึ้น (ต่อท้ายพื้นที่รูปแบบ) และprint ที่พื้นที่รูปแบบ 2 บรรทัดที่สลับกับบรรทัดที่สามและสอง


3

อีกวิธีawk :

awk '{print $0; if ((getline L2)>0 && (getline L3)>0){ print L3 ORS L2 }}' file

ผลลัพธ์:

gi_1234
I have a cat.
My cat is blue.
gi_5678
I also have a dog.
My dog is orange.

  • (getline L2)>0 && (getline L3)>0- แยก2ระเบียนถัดไปถ้ามีอยู่

  • แต่ละระเบียนที่ 2 และ 3 จะถูกกำหนดให้กับL2และL3ตัวแปรตามลำดับ


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

@DennisWilliamson เปลี่ยนเป็นตัวพิมพ์ใหญ่
RomanPerekhrest

1

การใช้perlและสคริปต์สั้น ๆ :

user@pc:~$ cat input.txt 
gi_1234
My cat is blue.
I have a cat.
gi_5678
My dog is orange.
I also have a dog.

user@pc:~$ perl -ne '$l2=<>; $l3=<>; print $_,$l3,$l2;' input.txt 
gi_1234
I have a cat.
My cat is blue.
gi_5678
I also have a dog.
My dog is orange.

สคริปต์ประมวลผลไฟล์ทั้งหมดสำหรับแต่ละบรรทัด (เก็บไว้ใน$_) มันจะได้รับสองบรรทัดถัดไป ( $l2และ$l3) และพิมพ์ตามลำดับที่ร้องขอ: line1, line3, line2


1

วิธีหนึ่งอาจเป็นดังนี้:

sed -e '
   /\n/s/\(.*\)\(\n\)\(.*\)/\3\2\1/;//b
   $!N;$q;N;                            # load up the pattern space with 3 lines provided eof not reached
   P;D;                                 # first just print the first line then interchange the two and print them
' yourfile

อีกวิธีหนึ่งคือ

perl -ne 'print $_, reverse scalar <>, scalar <>' yourfile

ผล

gi_1234
I have a cat.
My cat is blue.
gi_5678
I also have a dog.
My dog is orange.

1

ทำไมไม่เพียงแค่ทำสักครู่ห่วง? ในรูปแบบขยาย:

( while read a
  do
    read b
    read c
    echo "$a"
    echo "$c"
    echo "$b"
  done
) < input.txt

ใน "รูปแบบบรรทัดเดียว":

( while read a ; do read b ; read c ; echo "$a" ; echo "$c" ; echo "$b" ; done) < input.txt

ขาออก:

gi_1234
I have a cat.
My cat is blue.
gi_5678
I also have a dog.
My dog is orange.

1

Perl

perl -ne 'print if $.%3==1;$var=$_ if $.%3==2;print $_ . $var if $.%3==0' input.txt

แนวคิดนี้คือเราใช้ตัวดำเนินการโมดูโล%กับ$.ตัวแปรหมายเลขบรรทัดเพื่อหาว่าอันใดคืออันแรกทุกอันอันใดอันหนึ่งทุกวินาทีและอันไหนคือทุกบรรทัดที่ 3 สำหรับทุก ๆ ที่เหลือของบรรทัดที่ 3 คือ 0 ในขณะที่สำหรับทุก ๆ ที่ 1 และที่ 2 มันจะมีตัวเลขที่เกี่ยวข้อง

ทดสอบ:

$ cat input.txt                                                                                                          
gi_1234
My cat is blue.
I have a cat.
gi_5678
My dog is orange.
I also have a dog.

$ perl -ne 'print if $.%3==1;$var=$_ if $.%3==2;print $_ . $var if $.%3==0' input.txt                                    
gi_1234
I have a cat.
My cat is blue.
gi_5678
I also have a dog.
My dog is orange.

การปรับปรุงเล็กน้อย

วิธีการในการจัดเก็บบรรทัดที่สองลงในตัวแปรมีข้อบกพร่อง จะเกิดอะไรขึ้นถ้าบรรทัดสุดท้ายคือ "วินาที" อันที่หนึ่งนั่นคือส่วนที่เหลือของหมายเลขบรรทัดนั้นคือ 2 รหัสต้นฉบับในคำตอบของฉันและ DopeGhoti จะไม่พิมพ์My dog is orangeออกมาหากเราเว้นบรรทัดสุดท้าย การแก้ไขในกรณีทั้งสองนี้คือการใช้การEND{}บล็อกรหัสโดยไม่ต้องตั้งค่าตัวแปรชั่วคราวหลังจากการพิมพ์ ในคำอื่น ๆ :

$ awk 'NR%3 == 1 { print } NR%3 == 2 { delay=$0 } NR%3 == 0 { print; print delay;delay=""}END{print delay}' input.txt

และ

$ perl -ne '$s=$_ if $.%3==2;print $_ . $s and $s="" if $.%3==0 or $.%3==1;END{print $s}' input.txt 

วิธีนี้รหัสจะทำงานกับจำนวนบรรทัดโดยพลการในไฟล์ไม่ใช่แค่หารด้วย 3

การแก้ไขเพิ่มเติมสำหรับปัญหาที่กล่าวถึงในความคิดเห็น

ในกรณีของ awk หากบรรทัดสุดท้ายในไฟล์สร้างเอาต์พุต 1 สำหรับ $ % 3 รหัสก่อนหน้ามีปัญหาในการแสดงบรรทัดว่างใหม่เนื่องจากไม่มีการพิมพ์END{print delay}เนื่องจากprintฟังก์ชันที่กล่าวถึงในความคิดเห็นจะเพิ่มบรรทัดใหม่ให้กับตัวแปรที่ทำงานอยู่เสมอ ในกรณีของperlรุ่นปัญหานี้จะไม่เกิดขึ้นเนื่องจากด้วยฟังก์ชั่น-neค่าสถานะprintจะไม่เพิ่มบรรทัดใหม่

อย่างไรก็ตามการแก้ไขในกรณีของ awk คือทำตามเงื่อนไขดังกล่าวโดย Dope Ghoti ในความคิดเห็นคือการตรวจสอบความยาวของตัวแปรชั่วคราว รุ่น Perl ของการแก้ไขเดียวกันจะเป็น:

$ perl -ne '$s=$_ if $.%3==2;print $_ . $s and $s="" if $.%3==0 or $.%3==1;END{print $s if length $s}' input.txt 

1
การแก้ไขของคุณมีข้อบกพร่องเล็ก ๆ น้อย ๆ ที่เป็นไปได้ของมันเองซึ่งมันจะผนวกบรรทัดเอาต์พุตที่ว่างสำหรับไฟล์ที่มีจำนวนบรรทัด 'ผิด' ฉันได้รับการแก้ไขในการรวมตัวกันของฉันการปรับปรุงของคุณในคำตอบของฉันด้วย (สำหรับ)awk NR%3 == 0 { print; print delay; delay=""} END { if(length(delay) != 0 ) { print delay }
DopeGhoti

1
@DopeGhoti ปัญหาไม่ได้เกิดขึ้นกับ perl เนื่องจากการพิมพ์ของ perl กับ-neค่าสถานะไม่ได้ขึ้นบรรทัดใหม่ มันพิมพ์จริง ๆ แต่มันเป็นสตริงที่ว่างเปล่าไม่มีการขึ้นบรรทัดใหม่ อืมไม่มีฉันได้เพิ่มการกล่าวถึงปัญหาและการแก้ไขเดียวกันในคำตอบของฉัน ขอบคุณมาก!
Sergiy Kolodyazhnyy

1

เป็นกลุ่ม

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

บันทึกแมโครครั้งแรก:

gg qq j ddp j q

จากนั้นทำซ้ำจำนวนครั้งที่ต้องการ:

@q @q @q ...

หรือเพียงแค่เช่น

3@q

คำอธิบาย:

  • gg - ไปที่บรรทัดแรก
  • qq - เริ่มบันทึกแมโคร
  • j - ไปที่บรรทัดที่สอง
  • ddp - สลับบรรทัดที่สองและบรรทัดที่สาม
  • j - ไปที่บรรทัดที่สี่กล่าวคือบรรทัดแรกของสามบรรทัดถัดไป
  • q - หยุดการบันทึก
  • @q - เล่นซ้ำแมโครอีกครั้ง
  • 3 @ q - เล่นซ้ำแมโครสามครั้ง

1
แทนที่จะทำซ้ำด้วยตนเอง@q @q @qมันเป็นไปได้ที่จะทำเช่นนี้3@q- ทำซ้ำสามครั้ง 100@q- ทำซ้ำมาโคร 100 ครั้ง
MiniMax

0

การใช้งาน: ./shuffle_lines.awk input.txt

ตรวจสอบ shebang #!/usr/bin/awk -fเนื่องจากawkตำแหน่งอาจแตกต่างกันในระบบของคุณ

#!/usr/bin/awk -f

{
    if ((NR + 1) % 3 == 0) {
        buffer = $0;
    } else if (NR % 3 == 0) {
        print $0 ORS buffer;
        buffer = "";
    } else {
        print;
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.