sed를 사용하여 두 줄을 검색하고 그 앞에 한 줄을 삽입하세요.

sed를 사용하여 두 줄을 검색하고 그 앞에 한 줄을 삽입하세요.

소스 파일에는 다음이 포함됩니다.

# launch our autostart apps (if we are on the correct tty and not in X)
if [ "`tty`" = "/dev/tty1" ] && [ -z "$DISPLAY" ] && [ "$USER" = "pi" ]; then
    bash "/opt/retropie/configs/all/autostart.sh"
fi

검색 문자열은 다음과 같습니다.

if [ "`tty`" = "/dev/tty1" ] && [ -z "$DISPLAY" ] && [ "$USER" = "pi" ]; then
    bash "/opt/retropie/configs/all/autostart.sh"

rebootWithoutWiimotes=0 /home/pi/attachwii.sh이 줄 앞에 추가하여 다음과 같이 보이도록 하고 싶습니다 .

# launch our autostart apps (if we are on the correct tty and not in X)

rebootWithoutWiimotes=0 /home/pi/attachwii.sh

if [ "`tty`" = "/dev/tty1" ] && [ -z "$DISPLAY" ] && [ "$USER" = "pi" ]; then
    bash "/opt/retropie/configs/all/autostart.sh"
fi

나는 다양한 sed명령을 시도했고 달성할 수 있었습니다.sudo sed -i '\% bash "/opt/retropie/configs/all/autostart.sh"%i rebootWithoutWiimotes=0 /home/pi/attachwii.sh' 10-retropie.sh

이로 인해 잘못된 파일이 생성됩니다.

# launch our autostart apps (if we are on the correct tty and not in X)
if [ "`tty`" = "/dev/tty1" ] && [ -z "$DISPLAY" ] && [ "$USER" = "pi" ]; then
rebootWithoutWiimotes=0 /home/pi/attachwii.sh
    bash "/opt/retropie/configs/all/autostart.sh"
fi

내가 시도하면 :

sudo sed -i '\% if [ "`tty`" = "/dev/tty1" ] && [ -z "$DISPLAY" ] && [ "$USER" = "pi" ]; then bash "/opt/retropie/configs/all/autostart.sh"%i rebootWithoutWiimotes=0 /home/pi/attachwii.sh%' 10-retropie.sh

원본 파일에서 어떤 변경 사항도 얻지 못했습니다. 다음과 같이 해도 작동하지 않습니다.

sudo sed -i '\% if [ "`tty`" = "/dev/tty1" ] && [ -z "$DISPLAY" ] && [ "$USER" = "pi" ]; then%i rebootWithoutWiimotes=0 /home/pi/attachwii.sh' 10-retropie.sh

며칠 동안 다양한 변형을 테스트하고 sed정규식에 대해 많은 것을 배웠지만 이 부분은 이해할 수 없습니다.

sed파일의 정확한 부분이 있는지 확인하기 위해 이 두 줄을 검색한 다음 이 두 검색 줄 앞에 추가하려는 줄을 추가하려면 어떻게 해야 합니까 ?

답변1

이것은 sed에서 수행하는 PITA이지만 sedPerl에서는 상당히 쉽습니다(sed에서 가능하다고 100% 확신하지도 못합니다... 아마도 그럴 것입니다. 하지만 sed를 사용하여 시도해 볼 필요는 없을 것이라고 확신합니다. 이 작업을 수행).

#!/usr/bin/perl

use strict;
my $found = undef;

my $insert = "rebootWithoutWiimotes=0 /home/pi/attachwii.sh";

my @lines = (<>); # slurp entire file in @lines array

# iterate over @lines, looking for our two consecutive lines
foreach my $i (0 .. $#lines) {
  # abort if we've already inserted the line
  exit 1 if $lines[$i] =~ m:\Q$insert\E:;

  if (     $lines[$i  ] =~ m:if.*tty.*/dev/tty1.*DISPLAY.*USER.*pi:
        && $lines[$i+1] =~ m:bash "/opt/retropie/configs/all/autostart.sh":
     ) {
    $found = $i;
    last;
  };
};

# if we found them, insert our new line immediately before them.
if (defined($found)) {
  splice @lines, $found, 0, "$insert\n";
  print @lines;
} else { exit 1 };

\Q정규식 일치에 사용할 때 Perl에게 \E정규식 메타 문자를 이스케이프 처리하여 $insert문자열 리터럴로 처리하도록 지시합니다.

예를 들어 다른 이름으로 저장하고 insert-attach.pl실행 가능하게 만들고 chmod +x insert-attach.pl다음과 같이 실행합니다.

$ ./insert-attach.pl 10-retropie.sh 
# launch our autostart apps (if we are on the correct tty and not in X)
rebootWithoutWiimotes=0 /home/pi/attachwii.sh
if [ "`tty`" = "/dev/tty1" ] && [ -z "$DISPLAY" ] && [ "$USER" = "pi" ]; then
    bash "/opt/retropie/configs/all/autostart.sh"
fi

좋습니다. 그러면 수정된 파일이 표준 출력으로 인쇄되지만 파일을 바꾸려고 합니다. 따라서 다음과 같이 실행하십시오.

$ ./insert-attach.pl 10-retropie.sh > 10-retropie.sh.new \
    && mv -fv 10-retropie.sh.new 10-retropie.sh
renamed '10-retropie.sh.new' -> '10-retropie.sh'

$ cat 10-retropie.sh
# launch our autostart apps (if we are on the correct tty and not in X)
rebootWithoutWiimotes=0 /home/pi/attachwii.sh
if [ "`tty`" = "/dev/tty1" ] && [ -z "$DISPLAY" ] && [ "$USER" = "pi" ]; then
    bash "/opt/retropie/configs/all/autostart.sh"
fi

원본 파일만 대체됩니다.만약에수정이 성공했습니다.

Perl에서 이 작업을 수행하는 다른 방법이 있습니다(그 중 일부는 입력 파일이 기가바이트의 텍스트와 같이 큰 경우 더 적합할 것입니다). 그러나 이것은 Perl을 사용하여 수행할 수 있는 방법에 대한 좋은 튜토리얼 예입니다.


그런데 필요한 경우 여러 행을 삽입할 수 있습니다. 이 함수의 마지막 매개변수 splice는 목록입니다.

예를 들어, 이는 개행 문자, 행 rebootWithout...및 다른 두 개의 개행 문자를 삽입합니다.

splice @lines, $found, 0, "\n", $insert, "\n\n";

@insert스칼라 변수 대신 배열을 사용할 수도 있습니다 . 하지만 단지 하나를 선택하는 대신 더 고유한 요소 중 하나를 확인하려면 $insert테스트를 수정해야 합니다.exit 1 if $lines[$i] =~ ....@insert$insert아니요원본 파일에 있을 겁니다.) 예를 들어:

#!/usr/bin/perl

use strict;
my $found = undef;

my @insert = (
  "\n",
  "# run the attachwii.sh script",
  "rebootWithoutWiimotes=0 /home/pi/attachwii.sh",
  "\n",
  "\n",
);

my @lines = (<>); # slurp entire file in @lines array

# iterate over @lines, looking for our two consecutive lines
foreach my $i (0 .. $#lines) {
  # abort if we've already inserted the line
  # (note: perl arrays start from 0, not 1, so $insert[2] is the third element)
  exit 1 if $lines[$i] =~ m:\Q$insert[2]\E:;

  if (     $lines[$i  ] =~ m:tty.*/dev/tty1.*DISPLAY.*USER.*pi:
        && $lines[$i+1] =~ m:bash "/opt/retropie/configs/all/autostart.sh":
     ) {
    $found = $i;
    last;
  };
};

# if we found them, insert our new lines immediately before them.
if (defined($found)) {
  splice @lines, $found, 0, @insert;
  print @lines;
} else { exit 1 };

관련 정보