파일에서 줄 순서 변경


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 [...]을 반환합니다. 그것을 알면, 우리는 입력이 0 일 때 출력 직후에 모듈러스가 2 인 라인에 입력을 저장합니다.


우리는 여기에 작은 결함이 있습니다. 내 답변, 사소한 개선 부분 참조
Sergiy Kolodyazhnyy 2018 년

잘 잡아 주셔서 감사합니다. 의 형식으로 답변에 수정 프로그램을 통합했습니다 NR%3 == 0 { print; print delay; delay=""} END { if(length(delay) != 0 ) { print delay }.
DopeGhoti 2016 년

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

즉, p현재 행을 찢어 내고, next one을 가져오고 , h낡은 것을 가져 오고 n, ext one을 가져옵니다 .Gp


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 (소문자)로 시작한다고 가정합니다. 그것들은 12와 13의 숫자처럼 보이기 때문에 가독성이 좋지 않습니다. 더 나은 선택은 line2등일 수 있습니다 .
추후 공지가있을 때까지 일시 중지되었습니다.

@DennisWilliamson, 대문자로 변경
RomanPerekhrest 17

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 루프를 만들지 않습니까? 확장 된 형태로 :

( 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 -ne 'print if $.%3==1;$var=$_ if $.%3==2;print $_ . $var if $.%3==0' input.txt

여기서 아이디어는 %라인 번호 $.변수가있는 모듈로 연산자 를 사용 하여 어느 것이 첫 번째인지, 어떤 것이 매초마다, 어느 것이 세 번째 줄인지 알아내는 것입니다. 모든 세 번째 줄의 나머지는 0이고, 첫 번째와 두 번째 줄마다 해당하는 숫자가 있습니다.

테스트:

$ 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입니까? My dog is orange마지막 줄을 생략하면 내 및 DopeGhoti의 답변에 원래 코드가 인쇄되지 않습니다 . 두 경우 모두에 대한 해결책은 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 -ne '$s=$_ if $.%3==2;print $_ . $s and $s="" if $.%3==0 or $.%3==1;END{print $s if length $s}' input.txt 

1
수정 사항은 '잘못된'행 수를 가진 파일에 대해 빈 출력 행을 추가한다는 점에서 사소한 결함이있을 수 있습니다. 나는 당신의 개선에 대한 당신의 대답을 (for awk)로 통합하여 이것을 고쳤습니다 NR%3 == 0 { print; print delay; delay=""} END { if(length(delay) != 0 ) { print delay }.
DopeGhoti 2016 년

1
@DopeGhoti perl의 -ne플래그로 인쇄 하면 줄 바꾸기가 출력되지 않으므로 perl에서는 문제가 발생 하지 않습니다. 실제로 인쇄되지만 null 문자열이며 후행 줄 바꿈이 없습니다. 그럼에도 불구하고 문제에 대한 언급과 동일한 수정 사항을 내 답변에 추가했습니다. 감사 !
Sergiy Kolodyazhnyy 2012 년

1

정력

긴 파일에는 적합하지 않지만 파일을 편집하고 예를 들어 일부 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

오두막을 확인 #!/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.