web-dev-qa-db-ja.com

変数を設定するためのサブシェル内のプロセス置換

スクリプトをリモートで実行し、その標準出力を使用して変数を設定しようとしています。一時ファイルを回避するためにこれを行っています。

これが私が試しているパターンです:

var=$(bash <(curl -fsSkL http://remote/file.sh))
echo "var=${var}"

私はcurlを使わずにcatを使わずにこのパターンをテストしています:

var=$(bash <(cat ./local/file.sh))
echo "var=${var}"

このすべきは構文に関する限り同じです。 ./local/file.shにはecho helloが含まれているため、varには値helloが含まれていると想定しますが、残念ながら、上記の結果を実行すると次のようになります。

test.sh: command substitution: line 4: syntax error near unexpected token `('
test.sh: command substitution: line 4: `bash <(cat ./local/file.sh)'
var=

一時ファイルを使用せずに目標を達成するにはどうすればよいですか?

4
Sean Allred

これらは、シェルがPOSIXモードで実行されているときにbashでプロセス置換を実行しようとすると発生するエラーです。 bashシェルは、POSIXモードでのプロセス置換をサポートしていません。

bashは、次の場合にPOSIXモードで実行されます

  1. set -o posixが使用されている、または
  2. シェルはshとして呼び出されています。

私の直感は、あなたがスクリプトtest.shを持っているか、sh test.shで実行しているか、#!/bin/shのハッシュバング行があり、shがたまたまbashであることです。別の可能性は、スクリプトがnot#!- lineをまったく含まないこと、およびbash- as -shによって他の方法で呼び出されていることです。

代わりに、test.shスクリプトがbashによって呼び出されていることを確認してください。

例:

$ cat script.sh
echo hello
$ cat test.sh
var=$(bash <( cat script.sh ))
printf 'var="%s"\n' "$var"
$ bash -o posix test.sh
test.sh: command substitution: line 2: syntax error near unexpected token `('
test.sh: command substitution: line 2: `bash <( cat script.sh ))'
var=""
$ bash test.sh
var="hello"

POSIX shを使用してtest.shスクリプトで移植可能な方法でこれを行う場合:

var=$( cat script.sh | bash )
printf 'var="%s"\n' "$var"

これは、標準入力でbashの出力を読み取るcatプロセスに影響します。これはnot notプロセス置換バリアントと同じです(標準入力のみを残します)。これは、内部のbashシェルが実行するスクリプトが、その標準入力からデータの読み取りを行う場合に問題になります。

bashシェルの標準入力をそのままにする必要がある場合(そこから読み取る必要があるため)、mktempが使用可能であると想定して、

var=$( tmpfile=$(mktemp); cat script.sh >"$tmpfile" && bash "$tmpfile"; rm -f "$tmpfile" )
printf 'var="%s"\n' "$var"

cat script.shは、後でcurlコマンドに置き換えられると理解されています。

ファイル記述子のジャグリングに慣れている場合は、bashシェルを呼び出す前に、ファイル記述子3を標準入力記述子のコピーにして、フェッチされたスクリプトにそれを読み取らせることもできます。

var=$( exec 3<&0; cat script.sh | bash )
printf 'var="%s"\n' "$var"

次に、script.shスクリプトはread -u 3を使用してoriginal標準入力ストリームから読み取るか、utility <&3を使用してその入力ストリームを別のユーティリティにリダイレクトします。

12
Kusalananda