특정 행을 한 위치에서 다른 위치로 이동

특정 행을 한 위치에서 다른 위치로 이동

우분투 터미널을 사용하고 있는데 파일의 특정 줄(11번째 위치)을 첫 번째 줄로 이동한 다음 최종 결과를 새 파일로 전송해야 합니다. 원본 파일에는 수백 줄이 포함되어 있습니다.
지금까지 sed 명령 도구를 사용해 보았지만 원하는 효과를 얻지 못했습니다. 이것이 내가 지금까지 얻은 것입니다:

[mission 09] $ sed -n -e '1p' -e '11p' bonjour > bonjour2

하지만 새 파일에서는 첫 번째 줄과 11번째 줄만 표시됩니다. 하지만 새 파일이 나머지 원본 줄과 함께 원하는 개정 위치를 갖기를 원합니다.

입력하다:

English: Hello 
Turkish: Marhaba 
Italian: Ciao 
German: Hallo 
Spanish: Hola 
Latin: Salve 
Greek: chai-ray 
Welsh: Helo 
Finnish: Hei 
Breton: Demat 
French: Bonjour 

원하는 출력

French: Bonjour 
English: Hello 
Turkish: Marhaba 
Italian: Ciao 
German: Hallo 
Spanish: Hola 
Latin: Salve 
Greek: chai-ray 
Welsh: Helo 
Finnish: Hei 
Breton: Demat 

어떤 제안이 있으십니까?

답변1

사용(및 ed파생된 줄 편집기):sedgrep

printf '%s\n' '11m0' 'w bonjour2' 'q' | ed -s bonjour

11m0이렇게 하면 파일에 편집 명령이 적용되어 첫 번째 줄 앞으로 11번째 줄이 이동됩니다. 그런 다음 생성된 문서를 파일에 쓰고 bonjour2종료됩니다.

또는:

printf '%s\n' '11m0' ',p' 'Q' | ed -s bonjour >bonjour2

...명령을 사용하여 특정 파일에 쓰는 대신 ed전체 파일을 표준 출력으로 인쇄합니다. 그런 다음 결과는 새 파일 이름으로 리디렉션됩니다. 이 ,p명령(약어로 약칭 1,$p)은 전체 문서를 표준 출력으로 출력하고 Q강제 종료합니다(문서가 변경된 경우에도).

문서를 제자리에서 변경하려면(예: 원본 파일 변경) 결과를 파일 자체에 다시 씁니다.

printf '%s\n' '11m0' 'wq' | ed -s bonjour

위 변형 중 하나의 실행 예:

$ printf '%s\n' '11m0' ',p' 'Q' | ed -s bonjour >bonjour2
$ cat bonjour2
French: Bonjour
English: Hello
Turkish: Marhaba
Italian: Ciao
German: Hallo
Spanish: Hola
Latin: Salve
Greek: chai-ray
Welsh: Helo
Finnish: Hei
Breton: Demat

항상 움직여마지막줄을 맨 위로 이동 하려면 $m0대신 을 사용하세요 11m0. 항상 문자열로 시작하는 줄을 이동하려면 를 French:사용하세요 /^French:/m0.

답변2

sed -n '1h;2,10H;11G;11,$p' 

첫 번째 줄은 h개행으로 인해 복사된 후 H10에 추가됩니다.

존재하다11번째 줄, 예약된 공간 확보

~에서11 종료하고 인쇄합니다.


]#  sed -n '1h;2,10H;11G;11,$p' bonj 
French: Bonjour 
English: Hello 
Turkish: Marhaba 
Italian: Ciao 
German: Hallo 
Spanish: Hola 
Latin: Salve 
Greek: chai-ray 
Welsh: Helo 
Finnish: Hei 
Breton: Demat 

이게 낫다:

]# seq 20 | sed -n '1h;2,10H;11G;11,$p' 
11
1
2
3
4
5
6
7
8
9
10
12
13
14
15
16
17
18
19
20

나는 당신을 예로 들어 보겠습니다.

]# sed -e 1p -e 11p -n bonj 
English: Hello 
French: Bonjour 

... -n끝에 있는 스위치는 두 표현식 모두에 작동한다는 것을 보여주기 위한 것입니다.

나 또한 -n, 그렇다면 1h;2,10H이것은 , 이것은 1,10H, 이것은범위줄 번호 및 "hold"(저장) 명령. 아직 아무것도 인쇄되지 않았습니다.

11,$p또 다른 범위입니다. 11행에서는 예약 상태(예: 1-10)에서 방금 반환한 내용 "11G"를 인쇄하고 11행에 추가합니다.

$까지의 12번째 줄은 -n.


나는 -e당신처럼 두 가지를 해야 합니다:

sed -n -e '1h;2,10H' -e '11G;11,$p'

1,10부터 보류하고 11,$부터 인쇄합니다.


11번째 줄이 먼저 G이고 그 다음 p이 중요합니다.

]# seq 20 | sed -n -e '1h;2,10H' -e '11,$p;11G'
11
12
13
14
15
16
17
18
19
20

여기서 12번째 줄은 11번째 줄에 인쇄된 내용을 지웁니다.


매개변수가 있는 함수로

11번째 줄은 "putfirst" 함수 때문에 항상 지루합니다:

]# declare -f putfirst 
putfirst () 
{ 
    e="1h;2,$(($1-1))H;${1}G;${1},\$p";
    sed -ne "$e" $2
}

두 단계: 문자열 생성, 그 다음 sed 호출. "$"에는 두 가지 의미가 있습니다. "p"는 변수가 아닙니다!

유효한 가장 낮은 숫자는 다음과 같습니다.

]# seq 7 | putfirst 3 
3
1
2
4
5
6
7

또는 원본 "bonj" 파일을 사용하세요.

]# putfirst 4 bonj | putfirst 6 |head -4
Latin: Salve 
German: Hallo 
English: Hello 
Turkish: Marhaba 

이것은 연속된 두 개의 sed이지만 이제 두 개의 작업이 완료되었습니다.


진주

perl -ne '$n++; $h.=$_ if $n<11; print $_.$h if $n==11; print if $n>11' <(seq 20)

일부 스크립트와 마찬가지로 파일 이름이 필요하고 옵션이 필요하지 않습니다.

$want=11 ;
while (<>) {
    $n++ ;
    if ($n < $want)            # before $want: store line
        { $lowlines .= $_ ; 
          next }               # next line (avoids 'else')  
    if ($n == $want)           # at line $want: append stored lines to $_    
        { $_ .= $lowlines }   
    print ;                    # print $_ for $n not less than $want
}

AWK(Ed에서 훔친 것입니다(편집자가 아닙니다!))

NR < 11 { 
    buf[NR] = $0; next 
}
NR >=11 {
    print
    if (NR == 11) {
        for (i=1; i<11; i++) { print buf[i] }
    }
}

나는 NR증가 대신에 사용하여 n프로세스를 더 명확하게 만듭니다. 동일한 "트릭": next다운스트림을 단순화합니다.


그리고perl -n

$n++ ;
$tmp = $tmp . $_  if $n < 11  ; 
print  $_ . $tmp  if $n == 11 ;
print  $_         if $n > 11  ;

이것이 가장 좋은 형식입니다. 대칭.

답변3

내가 올바르게 이해했다면 행 11만 첫 번째 행으로 이동하고 싶을 것입니다.

따라서 원본이 다음과 같다면

Original line 1
Original line 2
...
Original line 18
Original line 19
Original line 20

그러면 결과는

Original line 11
Original line 1
Original line 2
...
Original line 9
Original line 10
Original line 12
Original line 13
...
Original line 19
Original line 20

이는 다음을 통해 달성할 수 있습니다.파일을 반복하지만 첫 번째 패스는 짧아질 수 있으므로 너무 끔찍하지는 않습니다.

( sed -n '11 {p;q}' file ; sed 11d file ) > newfile

기본적으로 첫 번째 sed명령은 11행을 인쇄한 다음 종료됩니다. 두 번째 sed명령은 각 줄을 인쇄합니다.와는 별개로11호선.

결과적으로 라인 11은 실제로 새 파일의 앞으로 이동됩니다.

답변4

그리고 POSIX sed:

$ sed -e '1,11!b' -e '11!H;1h;11!d;G' file

사용 perl:

$ perl -lne '
   push(@A,$_),next if $. < 11;
   print for $_, splice @A;
' file

사용 bash:

$ (head -n 11 - | tee log | tail -n 1 -; head -n 10 log; cat -;) < file

관련 정보