와일드카드 입력에 새 파일 이름을 쓰는 방법은 무엇입니까?

와일드카드 입력에 새 파일 이름을 쓰는 방법은 무엇입니까?

나는 과학 인턴십 동안 주로 와 같은 몇 가지 유틸리티를 사용하여 Inix 터미널을 사용하는 경험을 얻었 지만 grep, 내가 해야 할 숫자를 더 효율적으로 처리할 수 있도록 한동안 알아내려고 노력한 것이 하나 있습니다. .awksed

run.awk많은 수의 텍스트 파일에 대해 일부 작업을 수행하는 스크립트가 있습니다 . 실제로 파일을 가져와서 chloride.out데이터를 추출하고 작성합니다 chloride.cm.

어쨌든 이 스크립트가 쉘의 초기 와일드카드 문구를 기반으로 파일을 수신하고 쓰도록 할 수 있습니까 *.out?*.cm

많은 양의 데이터를 처리하기 위해 작성한 스크립트의 수가 백 번이 넘었고 정말 짜증납니다.

이상적으로는 모든 스크립트에 대해 셸을 통해 이 작업을 수행할 수 있는 방법이 있는지 알고 싶습니다. 셸이나 그에 상응하는 도구에서 자동화할 수 없는 경우 최소한 awk제가 설명한 것과 유사한 방식으로 스크립트를 자동화할 수 있습니까?

답변1

물론 awk가 와일드카드를 통해 여러 파일을 처리하도록 할 수도 있습니다. 한 가지 제안은 이를 run.awk단일 파일을 받아들이고 단일 출력 파일을 생성하는 일반적인 "함수"로 유지 한 다음 입력 및 출력 파일 동화를 담당할 수 있는 다른 스크립트에서 호출하는 것입니다.

이것은 Bash 스크립트가 될 것이며 이라고 부를 수 있습니다 awk_runner.bash.

#!/bin/bash

for ifname in *.out; do 
  ofname=${ifname/.out/.cm}
  printf "IN: %s, OUT: %s\n" $ifname $ofname
  printf "running run.awk with %s & %s\n\n" $ifname $ofname

  run.awk $ifname $ofname
done

샘플 실행

일부 테스트 파일이 포함된 샘플 디렉터리를 만들었습니다.

$ touch file{1..4}.out

그 결과 4개의 파일이 생성되었습니다.

$ ls -1
file1.out
file2.out
file3.out
file4.out

이제 스크립트를 실행합니다.

$ ./awk_runner.bash
IN: file1.out, OUT: file1.cm
running run.awk with file1.out & file1.cm

IN: file2.out, OUT: file2.cm
running run.awk with file2.out & file2.cm

IN: file3.out, OUT: file3.cm
running run.awk with file3.out & file3.cm

IN: file4.out, OUT: file4.cm
running run.awk with file4.out & file4.cm

"running..."으로 시작하는 각 줄 다음에 스크립트를 여기에서 실행할 수 있습니다.

목록의 파일

와일드카드를 사용하는 대신 *.out파일 이름 목록이 포함된 파일을 사용한다고 가정해 보겠습니다. 예:

$ cat filelist.txt 
file1.out
file2.out
file3.out
file4.out

while루프 대신 루프를 사용하는 수정된 버전의 스크립트를 사용할 수 있습니다 for. 이제 이 스크립트의 변형을 다음과 같이 부르겠습니다 awk_file_runner.bash.

#!/bin/bash

while read ifname; do 
  ofname=${ifname/.out/.cm}
  printf "IN: %s, OUT: %s\n" $ifname $ofname
  printf "running run.awk with %s & %s\n\n" $ifname $ofname

  run.awk $ifname $ofname
done < filelist.txt

이 버전의 스크립트는 파일에서 입력을 읽습니다 filelist.txt.

done < filelist.txt

그런 다음 루프가 반복될 때마다 명령을 사용하여 입력 파일에서 한 줄을 읽습니다 while.read

while read ifname; do

awk그런 다음 파일의 각 줄을 반복하면서 스크립트를 실행하는 첫 번째 스크립트와 동일한 방식으로 모든 작업을 수행합니다 .run.awk

답변2

쉘 래퍼를 작성하고 처리하는 각 파일에 대해 새로운 awk 인스턴스를 생성하는 대신 awk에서 직접 이 작업을 수행할 수 있습니다. awk 스크립트가 이미 있는 경우 FILENAME 변수를 사용하여 현재 파일에 액세스할 수 있습니다. 따라서 를 실행하면 awk 'some commands' file1 file2FILENAME을 사용하여 file1을 사용하고 있는지 file2를 사용하고 있는지 알 수 있습니다. >on / in awk 를 사용할 수도 있습니다 print. printf따라서 이와 같은 awk 스크립트가 있다면

/pattern/{ print $1,$3 }

넌 쉽게 할 수 있어

/pattern/{ print $1,$3 > FILENAME".processed" }

또는 이를 사용하여 FNR=1새 파일에 있는 시기를 알려주고 파일 이름으로 더 복잡한 조작을 수행하는 변수를 만듭니다. .in확장을 다음과 .out같은 것으로 바꾸는 것과 같습니다 .

sauer@humpy:/tmp$ grep . file*.in
file1.in:a
file1.in:b
file2.in:c
sauer@humpy:/tmp$ awk 'FNR=1{out=FILENAME;sub("\.in$",".out",out)} {print "processed"$0 > out}' file*.in
sauer@humpy:/tmp$ grep . file*.out
file1.out:processeda
file1.out:processedb
file2.out:processedc

나는 이것을 사용하여 grep .여기에 파일 이름과 여러 파일의 내용을 표시하는데, 이는 또한 흥미로운 트릭입니다. 그러나 변수 값을 out1로 변경하면 수정된 버전으로 설정한 다음(파일의 라인 1에 있음) 모든 인쇄를 로 리디렉션하는 것이 중요합니다. 확장자는 그렇지 않기 때문에 약간 위험합니다. 일치하면 대체가 이루어지지 않아 입력 파일을 덮어쓰게 됩니다. 따라서 이를 보장하기 위해 안전 장치 검사를 추가하는 것이 좋습니다. 이것은 독자들에게 연습문제로 남겨둔다. ;)FILENAMEFNRoutout != FILENAME

파일 이름 목록이 포함된 파일이 필요한 경우 가장 쉬운 방법은 다음과 같이 실행하는 것입니다.

awkscript $(< /path/to/filename_list_file )

콘텐츠를 가져와서 filename_list_file명령줄에 넣습니다.

관련 정보