awkなしである列から別の列に結合されたパスを印刷する方法は?

awkなしである列から別の列に結合されたパスを印刷する方法は?

awk次のコマンドと同じ機能を達成したいと思います。

awk  -F ";" '{print $3 >  "/" $1 "/" $2}' file

たとえば、

入力として2行のファイルがあります。

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)、この問題を解決することができ、あまりにも多くの場合、同時に開いているファイルの数に制限を置くいくつかの実装とは対照的です。

または、次のこともできます(POSIXsh構文)。

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

関連情報