awk 없이 한 열에서 다른 열로 결합된 경로를 인쇄하는 방법은 무엇입니까?

awk 없이 한 열에서 다른 열로 결합된 경로를 인쇄하는 방법은 무엇입니까?

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

관련 정보