파일에서 sed를 사용하여 수행된 대체 수를 계산하고 반환합니다.

파일에서 sed를 사용하여 수행된 대체 수를 계산하고 반환합니다.

큰 JSON 파일이 있는데 한 문자열을 다른 문자열로 바꾸고 싶습니다. 그렇게 해서는 안 되지만, 문자열을 바꾸고 싶지 않은 상황에서 문자열을 사용하는 것이 가능할 수도 있습니다.

올바른 컨텍스트에서 파일에서 해당 문자열이 몇 번 발생하는지 알고 있으므로 해당 문자열이 로 대체되는 횟수도 인쇄하고 싶습니다 sed. 어떻게 해야 합니까?

문자열을 찾아 바꾸려면 다음을 사용합니다.

sed -i "" "s/my_string/new_string/g" my_file.json

저는 Mac을 사용하고 있지만 Linux도 필요합니다. 예를 들면 다음과 같습니다.

sed -i "s/my_string/new_string/g" my_file.json

나는 a를 실행하여 grep파일에서 문자열을 찾고 다음과 같이 개수를 반환할 수 있다는 것을 알고 있습니다.

grep -o my_string my_file.json | wc -l

그러나 그것은 내가 묻는 것이 아닙니다. 텍스트 편집기(단어, 메모장, geany 등)처럼 수행할 수 있는 방법이 있는지 묻고 있습니다. 문자열을 주면 이 문자열을 보고 대체한 횟수를 알려줍니다. 하나.

추가 정보 - Bash 스크립트에서 실행되므로 다른 더 좋은 방법이 있다면 열려 있습니다.

답변1

그냥 perl대신 사용하세요. 이는 and 대체 연산자만큼 이식 가능하며 sed(이 경우 구문은 perl설치된 모든 시스템에서 동일하므로 이식성이 더 높습니다) -i대체 수를 인쇄하도록 지시할 수 있습니다.

perl -i  -lpe '$k+= s/my_string/new_string/g; END{print "$k"}' my_file.json

이렇게 하면 교체 작업이 수행되고 교체 번호가 표준 출력으로 인쇄됩니다.

답변2

sed를 사용해야 하는 경우 한 가지 접근 방식은 다음과 같습니다.

@Phillipos가 제안한대로 다음과 같이 변경하십시오.

sed -i "" -e '
  s/my_string/new_string\
/g;s/\n//w /dev/stdout
  s///g
' my_file.json | wc -l
  • my_string이 나타날 때마다 개행 문자 +를 넣으면 변경됩니다.
  • 그런 다음 sed가 인쇄할 때 암시적으로 개행 문자를 추가하므로 개행 문자를 제거합니다.
  • 대체가 성공한 경우에만 조건부로 stdout에 기록됩니다. 즉, 행에 my_string mng가 포함된 경우
  • 그런 다음 개행 마커를 제거합니다.

답변3

강제로 할 수 있다정력편집기는 스트리밍 모드에서 다음을 보고합니다.

ex -nsc 'redir! >/dev/stderr' -c '%s/pattern/PATTERN/g' -c 'redir END' -c 'wq' my_file

3 substitutions on 2 lines

ex-vim 모드(또는 vim -e)
-n--스왑 파일을 생성하지 마십시오
-s-스크립트
-c 명령줄 모드(또는 +'command')
'redir! >/dev/stderr'--쉘 표준 오류로 리디렉션
'redir END'-리디렉션이 종료됩니다. 생략 가능
'wq'-변경 사항을 저장하고 편집기를 종료합니다. 이를 로 바꾸면 'q!'출력을 얻고 예상한 것과 비교하기 위해 파일을 변경할 필요가 없습니다.

답변4

다음은 변경 사항과 영향을 받는 줄을 계산하는 간단한 awk 버전입니다.

#! /bin/bash

Awk='
BEGIN { fmtEnd = "Made %d substitutions on %d lines.\n"; }
{
    n = gsub (/exit/, "return");
    if (n) { Lines++; Count += n; }
    print;
}
END { printf (fmtEnd, Count, Lines) > "/dev/stderr"; }
'
    awk "${Awk}" doFifo > doFifo.fix

출력(stderr)은 다음과 같습니다. 카운트를 더 쉽게 복구할 수 있도록 재정렬할 수 있습니다.

Made 8 substitutions on 6 lines.

GNU/awk에는 -i inplace 확장자가 있지만 저는 내부 업데이트에 대해 매우 보수적입니다. 내 고객은 종종 자신의 데이터가 항상 100% 정확하다고 불평하고 주장하므로 감사 추적과 데이터의 모든 버전을 유지합니다.

다음은 변경된 각 줄을 기록하는 awk 변형입니다. 이것은 아직 프로덕션 수준이 아닙니다. 패턴과 대체를 인수로 받아들이고, 한 번의 실행으로 여러 파일을 처리하고, 입력을 기반으로 출력 파일의 이름을 지정하고, 파일 및 전체 합계별로 요약하기를 원합니다. 어쩌면 패턴 배열->교체도 허용할 수도 있습니다.

#! /bin/bash

AwkFull='
BEGIN {
    reFix = "exit"; txFix = "return";
    fmtEnd = "Made %d substitutions on %d lines.\n";
    fmtSub = "\n.... %d Changes on file %s line %d:\n";
    fmtSub = fmtSub "Was: %s\nNow: %s\n";
}
{
    New = $0;
    n = gsub (reFix, txFix, New);
    if (n == 0) { print $0; next; }

    Lines++; Count += n;
    printf (fmtSub, n, FILENAME, FNR, $0, New) > "/dev/stderr";
    print New;
}
END { printf (fmtEnd, Count, Lines) > "/dev/stderr"; }
'
    awk "${AwkFull}" doFifo > doFifo.fix

이는 변경된 각 줄을 보여줍니다. 예를 들면 다음과 같습니다.

.... 2 Changes on file doFifo line 64:
Was:    (exit)  printf 1>&7 '%(%T)T  Received exit command\n' -1
Now:    (return)    printf 1>&7 '%(%T)T  Received return command\n' -1

편집: 매개변수를 명령 매개변수로 전환했습니다.

위의 첫 번째 버전은 패턴과 대체 텍스트를 gsub 명령 자체에 포함합니다. 두 번째 버전에서는 (a) 이름을 지정하고 (b) 코드 헤드에서 선언하여 변경하기가 더 쉽습니다.

코드 일반화의 다음 단계는 셸에서 코드를 전달하는 것입니다. 이것은 awk에서는 쉽습니다. 먼저 reFix 및 txFix를 정의하는 줄을 삭제합니다. 규칙은 re정규식과 tx텍스트에 대한 것이지만 일관성이 있는 한 변수를 자유롭게 호출할 수 있습니다.

쉘 문자열을 awk 변수에 넣으려면 옵션이 있습니다 -v. 따라서 awk 명령은 다음과 같습니다.

awk -v reFix="exit" -v txFix="return" "${AwkFull}" doFifo > doFifo.fix

쉘 변수 사용의 마지막 단계는 모든 형태의 쉘 대체를 사용하는 것입니다. 예를 들면 다음과 같습니다.

awk -v reFix="${1}" -v txFix="${myNew}" "${AwkFull}" doFifo > doFifo.fix

두 가지(아마도 그 이상) 단점이 있습니다.

(1) awk는 이것이 /exit/패턴이라는 것을 알고 있습니다. 어떤 경우에는 구문을 명확히 해야 할 수도 있습니다. 예를 들어 간단한 줄 일치는 /exit/로 다시 작성해야 $0 ~ reFix하지만 awk는 첫 번째 인수가 gsub()패턴이라는 것을 알고 있으므로 구문이 변경되지 않습니다. (바라보다https://www.gnu.org/software/gawk/manual/gawk.html#Strong-Regexp-Constants더 알아보기. )

(2) 변수의 패턴은 awk 프로그램을 처음 읽을 때 구문 검사를 받지 않으며, 사용할 때만 구문 검사를 받습니다. 따라서 사용자가 입력한 패턴은 모호한 오류 메시지로 인해 런타임 중에 쉽게 중단될 수 있습니다.

관련 정보