複数のプロセス置換を組み合わせる

複数のプロセス置換を組み合わせる

次のようなことを試したとします。

$ paste ../data/file-{A,B,C}.dat

そして、貼り付ける前に各ファイルを(数値順に)並べ替えたいことに気付きました。次に、プロセス置換を使用して、次のように記述する必要があります。

$ paste <(sort -n ../data/file-A.dat) \
        <(sort -n ../data/file-B.dat) \
        <(sort -n ../data/file-C.dat)

ここでは重複が多く見られますが、これは好ましくありません。各プロセス置換は互いに分離されているため、複数のプロセス置換にまたがる中括弧展開やパス名展開 (ワイルドカード) は使用できません。

これをコンパクトな方法で記述し (たとえば、sort -nと を../data/file-{A,B,C}.dat別々に指定する)、コマンドライン全体を構成できるツールはありますか?

答え1

次のようにすることができます:

eval paste '<(sort -n ../data/file-'{A,B,C}'.dat)'

または関数として自動化する

sort_paste() {
  local n i cmd
  n=1 cmd=paste
  for i do
    cmd="$cmd <(sort -n -- \"\${$n}\")"
    n=$(($n + 1))
  done
  eval "$cmd"
}
sort_paste  ../data/file-{A,B,C}.dat

(実装によっては、を にksh置き換える必要があります)localtypeset

任意のコマンドに適応するには (そして、eval適切に使用すれば安全であることを証明するには)、次のようにします。

xproc() {
  local n i cmd stage stage1 stage2 stage3
  cmd= xcmd= stage=1 n=1
  stage1='cmd="$cmd \"\${$n}\""'
  stage2='xcmd="$xcmd \"\${$n}\""'
  stage3='cmd="$cmd <($xcmd \"\${$n}\")"'
  for i do
    if [ -z "$i" ] && [ "$stage" -le 3 ]; then
      stage=$(($stage + 1))
    else
      eval 'eval "$stage'"$stage\""
    fi
    n=$(($n + 1))
  done
  eval "$cmd"
}

xproc paste '' sort -n -- '' ../data/file-{A,B,C}/dat

答え2

参照してくださいここ、なぜeval使用すると危険なのか。お気づきのように、それは非常に強力なツール、しかし同時に大きな損害を引き起こす

次のスクリプトは、必要なことを安全に実行します。

sort_ps () 
{ 
    local cmd="$1" p=()
    shift;
    for f in "$@"; do
        p+=(<(sort -n "$f"));
    done
    "$cmd" "${p[@]}"
}

編集: Chazelas 氏の言う通りです。解決策を修正したので、sort_ps paste file1.txt file2.txt file2.txt ... fileN.txt代わりに を使用できます。私の回答を確認してくださった Stephane さん、ありがとうございます。

サンプル出力:

rany$ sort_ps sprunge foo1.txt foo.txt 
http://sprunge.us/EBZf?/dev/fd/62
http://sprunge.us/TQGC?/dev/fd/62

関連情報