awk
다음 명령과 동일한 기능을 달성하고 싶습니다 .
awk -F ";" '{print $3 > "/" $1 "/" $2}' file
예를 들어:
입력으로 두 줄이 포함된 파일이 있습니다.
path1;filename_1;f3_1
path2;filename_2;f3_2
내가 원하는 출력은 다음과 같습니다.
- 파일의
/path1/filename_1
내용은 다음과 같습니다.f3_1
- 파일의
/path2/filename_2
내용은 다음과 같습니다.f3_2
awk를 사용하여 이 작업을 수행하면 141 종료 코드 SIGPIPE가 표시됩니다. 이 오류를 우회하고 싶습니다.
답변1
awk
파일 핸들이 부족한 것 같습니다 . 최신 버전으로 업그레이드할 수 없는 경우 awk
가장 확실한 해결 방법은 해당 파일을 사용한 후 해당 파일을 닫는 것입니다.
path;filename
두 번 이상 발생할 가능성이 있는 조합이 있습니까 ?
그렇지 않은 경우 다음을 시도하십시오.
awk -F ";" '{f="/"$1"/"$2; print $3 > f ; close(f)}' file
그렇지 않고 >> f
기존 파일에 추가할 수 있으면 다음을 사용하십시오.
awk -F ";" '{f="/"$1"/"$2; print $3 >> f ; close(f)}' file
파일을 처음 작성할 때 잘라야 하지만 그 이후부터 추가해야 하는 경우 상황은 약간 더 복잡합니다.
awk -F ";" '{ f="/"$1"/"$2;
if ( !fnames[f]++ ) { print > f };
print $3 >> f;
close(f)
}' file
연관 fnames
배열은 스크립트가 파일 이름을 확인했는지 여부를 결정하는 데 사용됩니다. 그렇지 않은 경우 파일을 자릅니다.
답변2
awk
제 생각에는 이것은 의 기능과 완벽하게 일치 하기 때문에 어리석은 일입니다 . awk
다음을 수행할 수 있습니다( bash-4.3
구문).
(unset fds; typeset -A fds
while IFS=';' read -r a b c rest; do
file=/$a/$b
[[ ${fds[$file]} ]] || exec {fds[$file]}> "$file"
printf '%s\n' "$c" >&"${fds[$file]}"
done < file)
그러나 이는 효율성을 감소시킵니다(또한쉘 루프를 사용하여 텍스트를 처리하는 것이 왜 나쁜 습관으로 간주됩니까?awk
), 이 문제를 해결할 수 있고 너무 많은 경우 동시에 열려 있는 파일 수에 제한을 두는 일부 구현과는 대조적입니다 .
또는 다음을 수행할 수 있습니다(POSIX sh
구문).
while IFS=';' read -r a b c rest; do
printf '%s\n' "$c" >> "/$a/$b"
done < file
그러나 이렇게 하면 파일을 덮어쓰는 대신 파일에 텍스트가 추가됩니다(그리고 여전히 를 사용하는 것보다 훨씬 덜 효율적입니다 awk
).
이 작업도 수행할 수 있지만 파일을 열고 fd 목록을 수동으로 유지 관리하는 작업을 perl
다시 수행해야 합니다 .awk
perl -F ';' -lane '
$file = "/$F[0]/$F[1]";
unless (defined $fds{$file}) {
open $fds{$file}, ">", $file or die "$file: $!\n";
}
print {$fds{$file}} $F[2]' < file
(동시 파일 열기 제한과 동일한 잠재적인 문제가 있습니다).
답변3
사용 컷:
while read -r line ; do printf "in the file /%s/%s the content is %s\n" $(echo $line | cut -d';' -f1) $(echo $line | cut -d';' -f2) $(echo $line | cut -d';' -f3) ; done < file
더 짧은 버전(Stéphane Chazelas의 답변에서 일부 내용을 훔침)과 결과를 저장하기 위해 출력을 다른 파일로 리디렉션하는 방법도 있습니다.
while IFS=';' read -r f1 f2 f3 ; do printf "in the file /%s/%s the content is %s\n" $f1 $f2 $f3 ; done < files > file2