Gawk Inplace and Stdout


10

gawk-i inplace옵션 을 사용하여 인쇄 할 수도 stdout있습니까?

예를 들어, 파일을 업데이트하고 싶거나 변경 사항이 있으면 파일 이름과 변경된 줄을 인쇄하면 stderr다음과 같은 작업을 수행 할 수 있습니다

find -type f -name 'myfiles' -exec gawk -i inplace '{if(gsub(/pat/, "repl")) { print FILENAME > "/proc/self/fd/2" ; print > "/proc/self/fd/2"; } print;}' {} +

stdout대신 대신 사용 하거나 다른 스트림에 해당 블록을 인쇄하는 더 깨끗한 방법이 있습니까?


2
이 특별한 경우에 당신은 find -type f -name 'myfiles' -exec grep -q 'pattern' {} \; -print -exec gawk -i inplace '{do_your_sub_and_print_to_dev/stderr_too}' {} \;그런 식으로 무언가를 실행하고 싶을 것입니다. awk를 사용하여 실제로 그 패턴과 일치하는 줄을 포함하는 파일을 편집 할 것입니다.
don_crissti

@don_crissti 나는 종종 얼마나 빨리 grep할 수 있는지 잊어 버린다 . 내 첫 번째 본능은 파일을 두 번 "처리"하지 않아도되는 것이지만 그럼에도 불구하고 실제로 더 빠르더라도 놀라지 않을 것입니다. 그것은 단지 내가 프로파일 링 작업에 내 직감을 믿을 수있는 이유를 보여 간다
에릭 Renouf

1
예, 매우 빠르며 명심하십시오 : 1) 일치하는 -print -exec gawk것이 없으면 파일을 한 번만 처리하고 ( 더 이상이 실행되지 않는 부분 ) 2) 첫 번째 일치에서 중지하므로 첫 번째 일치가 마지막 줄은 여전히 ​​전체 파일을 두 번 처리하지 않습니다 (1.X 배와 비슷합니다). 또한, 만약 gawk -i inplace같은 작품 sed -i어쨌든 현재 위치에서 파일을 편집합니다 - 즉, 업데이트 타임 스탬프를 ... 편집에 아무것도 아이 노드 등이 없었다하더라도
don_crissti

답변:


13

당신은 사용해야 /dev/stderr또는 /dev/fd/2대신 /proc/self/fd/2. gawk핸들 /dev/fd/x/dev/stderr그 자체 (시스템에 해당 파일이 있는지 여부에 관계없이).

당신이 할 때 :

print "x" > "/dev/fd/2"

gawk않습니다 write(2, "x\n")당신이 할 때 동안 :

print "x" > "/proc/self/fd/2"

/proc/self/fd/x특별히 취급하지 않기 때문에 다음과 같은 일을합니다.

fd = open("/proc/self/fd/2", O_WRONLY|O_CREAT|O_TRUNC);
write(fd, "x\n");

첫 번째 /proc/self/fd는 Linux마다 다르며 Linux에서는 문제가 있습니다. 위의 두 버전은 stderr이 일반 또는 다른 검색 가능한 파일 또는 소켓 (후자가 실패하는 소켓) (파일 설명자를 낭비한다는 것은 말할 것도 없음)에 해당하지 않습니다.

즉, 원래 stdout에 쓰려면 다음과 같은 다른 fd에 저장해야합니다.

gawk -i inplace '{
   print "goes into the-file"
   print "to stdout" > "/dev/fd/3"}' the-file 3>&1

gawkstdout을 파일로 제자리로 리디렉션합니다. 예를 들어 다음과 같은 이유로 필요합니다.

awk -i inplace '{system("uname")}' file

uname출력 을 저장합니다 file.


2

그냥 재미를 위해, 단지 POSIX 사용하여 다른 접근 방식의 기능을 find, sh, grep그리고 (특히) ex:

find . -type f -name 'myfiles' -exec sh -c '
  for f do grep -q "pat" "$f" &&
    { printf "%s\n" "$f";
      printf "%s\n" "%s/pat/repl/g" x | ex "$f";
  }; done' find-sh {} +

위의 명령에서 모든 줄 바꿈은 선택 사항이며 하나의 라이너로 압축 될 수 있습니다.

또는 더 분명하게도

find . -type f -name 'myfiles' -exec sh -c '
  for f
  do
    if grep -q "pat" "$f"; then
      printf "%s\n" "$f"
      printf "%s\n" "%s/pat/repl/g" x | ex "$f"
    fi
  done' find-sh {} +

:)


(이 명령은 테스트를 거치지 않았습니다. 편집을하면 환영합니다.)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.