シェル関数:パイプシーケンスを引数として使用する

シェル関数:パイプシーケンスを引数として使用する

一時ファイルを生成し、パラメータ(すべてのパイプシーケンスを含む)を実行し、それを一時ファイルにリダイレクトしてから、VS Codeで開くシェル関数(.bashrc)があります。

私はシェル関数を次のように呼び出します。

Temp "ls | nl"

以下のコードではこれを機能させようとしています。 IFS をスペースとして使用して文字列全体を分離し、配列に保存します。今度はパイプラインシーケンス全体を実行し、最終的なstdoutを一時ファイルにリダイレクトしたいと思います。この目標をどのように達成できますか? forループがここで動作しないことを知っています。しかし、配列全体を印刷したいです。

Temp() {
    a="$(mktemp --suffix=.md "/tmp/$1-$(GetFilename "$2")-XXX")"
    IFS=' ' read -r -a Array <<< "$1"
    nArray=${#Array[@]} # Size of array
    for ((i=0; i<nArray; i=i+1)); do

    done
    #"${@}" > "$a"
    code -r "$a"
}

対話型端末セッションでは、次のことが機能します。

cat <<EOF
$(ls | nl)
EOF

だから私は関数内のforループの代わりにHeredocを使ってみました。

cat > "$a" <<EOF
$($1)
EOF

しかし、これは周囲に引用符が付いているので|失敗します。

上記のアプローチは、どういうわけか引用符を削除できれば効果的です。


これも機能しません

cat > "$a" <<EOF
$(echo $1 | sed "s/'//g")
EOF

ベストアンサー1

関数に引数として与えられたシェルコマンドを実行させるには、eval文字列でそれを使用する必要があります(例:print)FOO

eval_arg() {
    eval "$1"
}
eval_arg "echo foo |tr a-z A-Z"

"$1"パラメータ拡張後、パイプ、引用符、リダイレクトなどのシェル構文は処理されないため、単純な拡張は機能しません。最初の引数を配列に分割したり、$@実際には変更しません。


したがって、$(ls | nl)シェルで処理されるリテラルパイプ文字がありますが、$($1)値の特殊文字$1(ワードセパレータとワイルドカードを除く)はで処理されません。ここに引用符はありません。

最後の例では、$(echo $1 | sed "s/'//g")値をスペースに分割してから(デフォルトの単語分割を使用)、単語をスペース()で連結して入力に渡して、その中の単一引用符を削除します。$1IFSechosed

したがって:

$ set -- "'foo  bar'"
$ $(echo $1 | sed "s/'//g")
foo bar 

コマンドの外部引用符はsetシェルで処理され、内部引用符は値の一部です。これset -- 'foo bar'は引用符を含めず、$1ここにある唯一の引用符は一般的なシェル処理の一部として削除されます。

おすすめ記事