次のようなことを試したとします。
$ 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
置き換える必要があります)local
typeset
任意のコマンドに適応するには (そして、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