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

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

나는 주로 , , 같은 몇 가지 유틸리티를 사용하여 과학 인턴십을 하면서 Inix 터미널에 대한 경험이 있지만, grep나를 awk훨씬 sed더 효율적으로 만들어 줄 수 있는 방법을 한동안 알아내려고 노력해 왔습니다. 내가해야 할 숫자 처리로.

run.awk대규모 텍스트 파일 모음에 대해 일부 조작을 수행하는 스크립트가 있습니다 . 그대로 파일을 가져와서 chloride.out데이터를 추출하고 씁니다 chloride.cm.

어쨌든 이 스크립트를 사용하여 쉘의 초기 와일드카드 문구를 기반으로 파일을 *.out작성할 수 있습니까 ?*.cm

수백 번 이상 반복해야 했던 대량의 데이터를 처리하기 위해 작성한 스크립트의 양은 짜증스러울 뿐입니다.

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

답변1

와일드카드를 통해 여러 파일을 처리할 수 있는 것은 확실합니다. 한 가지 제안은 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 print/ awk에서도 사용할 수 있습니다 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 .여기에 파일 이름과 여러 파일의 내용을 표시하는 데 사용하고 있는데, 이것도 재미있는 트릭입니다. 그러나 중요한 것은 변수 값을 1로 변경 되는 out수정된 버전으로 설정한 다음(파일의 1번째 줄에 있음) 모든 인쇄물을 . 확장자와 일치하지 않으면 대체 항목이 없어 입력 파일을 덮어쓰게 되므로 이는 약간 위험합니다. 따라서 안전 장치 검사를 추가하여 이를 확인하는 것이 좋습니다 . 그것은 독자들의 연습 문제로 남겨졌습니다. ;)FILENAMEFNRoutout != FILENAME

파일 이름 목록이 포함된 파일이 필요한 경우 다음과 같이 실행하는 것이 가장 쉽습니다.

awkscript $(< /path/to/filename_list_file )

의 내용을 가져와서 filename_list_file명령줄에 입력합니다.

관련 정보