Gnu sed는 값을 추가하는 bash 함수를 실행할 수 있습니다.

Gnu sed는 값을 추가하는 bash 함수를 실행할 수 있습니다.

gnu sed는 어떻게 bash 기능을 실행하여 카운터 값을 증가합니까?

$ k(){ ((i++)); echo $i ;} ;export -f k
$ i=; echo -e 'oAo\nooAo\nAo' | sed -E '/A/e k'
1
oAo
1
ooAo
1
Ao

카운터를 올바르게 수행하는 대신 실패합니다.

답변1

프로세스는 상위 프로세스의 환경에 영향을 미칠 수 없습니다. sed의 명령을 사용하면 e새 셸을 포크하여 명령을 실행하고(내보낸 k함수를 상속함) 해당 셸 변수에 대한 모든 변경 사항은 i종료 시 손실됩니다(즉, k 함수가 hour를 종료함).

변수를 증가시키려면 환경 외부 어딘가에 변수를 저장해야 합니다. 예를 들어 파일에서. 파일을 사용하고 싶지 않다면 SQL 데이터베이스 같은 것을 사용하지 못할 이유가 memcached없습니다 redis.

예를 들어:

k() {
  local counterfile i
  counterfile='/tmp/counter.i'
  [ -e "$counterfile" ] && i=$(cat "$counterfile")
  ((i++))
  echo "$i" | tee "$counterfile"
}
export -f k

지금 실행하면 카운터가 증가합니다.

$ rm /tmp/counter.i
$ printf 'oAo\nooAo\nAo' | sed -E '/A/e k'
1
oAo
2
ooAo
3
Ao
$ echo 100 > /tmp/counter.i
$ printf 'oAo\nooAo\nAo' | sed -E '/A/e k'
101
oAo
102
ooAo
103
Ao

그런데, sed의 e명령이 유용하기는 하지만, 내 생각에는 Perl이 여러분이 하고 있는 작업에 더 나은 언어라고 생각합니다. 예를 들어

$ printf 'oAo\nooAo\nAo' |
    perl -lpe 'BEGIN { $i=shift || 0 };
               if (/A/) {print ++$i}' 10
11
oAo
12
ooAo
13
Ao

인수를 제공하지 않으면 $i기본값은 0입니다.

스크립트가 "sed"처럼 보이도록 하려면 $i포함된 줄에 카운터 변수를 증가시키고 인쇄하는 방법이 있습니다 A. 여기 또 다른 것이 있습니다:

/A/ && print ++$i

한 줄에 여러 일치 항목이 있을 수 있고 각 일치 항목에 대해 카운터를 증가시키고 인쇄해야 하는 경우 일치 항목을 반복해야 합니다. 예를 들어

$ printf 'oAo\noAoAoAo\nAo' |
    perl -lpe 'BEGIN { $i=shift || 0 };
               for (/oA/g) {print ++$i}'
1
oAo
2
3
4
oAoAoAo
Ao

또는 누적 합계가 필요하지 않지만 각 행의 일치 항목 수를 계산하는 경우:

$ printf 'oAo\noAoAoAo\nAo' |
    perl -lne '$c = () = $_ =~ /oA/g;
               printf "%02i:%s\n", $c, $_'
01:oAo
03:oAoAoAo
00:Ao

이 마지막 항목에는 설명이 필요할 수 있습니다. 읽어뒤로, 이 $c = () = $_ =~ /oA/g문은 먼저 정규식 일치를 수행 /oA/g하고 목록 컨텍스트의 결과를 빈 목록으로 반환한 ()다음 변수에 할당합니다 $c. 배열/목록이 아닌 스칼라 변수이기 때문에 $c스칼라 컨텍스트에서 평가되므로 해당 목록의 요소 수를 반환합니다. 이것은 일치 항목 수를 계산하는 데 사용되는 매우 일반적인 Perl 관용어입니다.


참고: Perl에는 -psed와 매우 유사하게 실행되도록 하는 옵션이 있습니다(즉, 입력을 반복하고 명령문이 인쇄를 방해하지 않는 한 처리 후 각 줄을 인쇄합니다). Perl에는 -n다음과 같이 동작하도록 하는 옵션이 있습니다 sed -n(입력을 반복하고 명시적으로 인쇄하라는 지시만 인쇄합니다).

마지막으로, 이 버전의 sed 및 bash 함수는 일치하는 각 입력 행에 대해 bash, cat및 를 분기한다는 점에 주목할 가치가 있습니다 . Perl 버전은 아무것도 포크하지 않고 입력만 반복합니다. bash에서 수행하기 위해 외부 프로그램을 포크해야 하는 많은 작업은 자체 내장 구문(또는 수천 개의 라이브러리 모듈 중 하나)을 사용하여 Perl을 통해 내부적으로 수행될 수 있다는 점도 주목할 가치가 있습니다.tee/A/

답변2

GNU sed를 사용하면 원하는 결과를 얻기 위해 사용자 정의 함수에 의존할 필요가 없습니다. 여기서는 증분 개수를 저장하기 위해 저장 공간을 사용합니다.

echo -e 'oAo\nooAoAoA\no' | 
sed -En "/A/!d
  p;:a
  H;g
  s/^(\n*).*/expr '\1' : '.*'/ep
  g;s//\1/;x;s/^\n*//;s/A//;//ba
"

산출:

oAo
1
ooAoAoA
2
3
4

관련 정보