私のRedhat 9、OpenBSD 4.9、FreeBSD 10、Macos X、LinuxMint 17.3、およびUbuntu 14.04.4は、次のコマンドを実行するとすべてOKで印刷されます.
myfunc() { echo OK; }
export -f myfunc
perl -e open\(\$fh,\"\|-\",\"@ARGV\"\)\;close\$fh\; /bin/bash\ -c\ myfunc\\\ a
私のUbuntu 16.04.1は以下を提供します。
bash: myfunc: command not found
しかし、削除するとうまく\\\ a
いきます。
perl -e open\(\$fh,\"\|-\",\"@ARGV\"\)\;close\$fh\; /bin/bash\ -c\ myfunc
私のシステムに何かが誤って設定されているようです。しかし、何を探すべきですか?
編集する
thrigは短いバージョンを見つけましたが、それも失敗しました。これを使用して、失敗したシステムと失敗していないシステムを追跡しました。
stdout strace -ff perl -e 'system @ARGV' /bin/bash\ -c\ myfunc\\\ a|grep bash
失敗する:
execve("/usr/bin/perl", ["perl", "-e", "system @ARGV", "/bin/bash -c myfunc\\ a"], [/* 71 vars */]) = 0
[pid 7728] execve("/bin/sh", ["sh", "-c", "/bin/bash -c myfunc\\ a"], [/* 71 vars */]) = 0
[pid 7729] execve("/bin/bash", ["/bin/bash", "-c", "myfunc a"], [/* 70 vars */]) = 0
失敗なし:
execve("/usr/bin/perl", ["perl", "-e", "system @ARGV", "/bin/bash -c myfunc\\ a"], [/* 20 vars */]) = 0
[pid 26497] execve("/bin/sh", ["sh", "-c", "/bin/bash -c myfunc\\ a"], [/* 20 vars */]) = 0
[pid 26498] execve("/bin/bash", ["/bin/bash", "-c", "myfunc a"], [/* 20 vars */]) = 0
とても似ているようです。\\\ a
両方のシステムから指定された項目を削除します。
execve("/usr/bin/perl", ["perl", "-e", "system @ARGV", "/bin/bash -c myfunc"], [/* 71 vars */]) = 0
[pid 7826] execve("/bin/bash", ["/bin/bash", "-c", "myfunc"], [/* 71 vars */]) = 0
sh -c
したがって、Perlはコマンドが1つしかない場合は削除します。sh -c
Ubuntu 16.04の機能を活用してみましょうか?
/bin/sh
dash
両方のシステムで。
編集2
env
この機能を見せてください。これは、両方のシステムで環境の一部である機能を示しています。
perl -e 'system @ARGV' /bin/bash\ -c\ env
Ubuntu 16.04とオペレーティングシステム1つ:
BASH_FUNC_myfunc%%=() { echo OK
}
その他の作業システム:
BASH_FUNC_myfunc()=() { echo OK
}
ただし、これは作業システムの定義のみを示しています。
perl -e 'system @ARGV' /bin/bash\ -c\ env';true'
編集3
解決策:
myfunc() { echo OK; }
export -f myfunc
perl -e open\(\$fh,\"\|-\",@ARGV\)\;close\$fh\; /bin/bash -c myfunc\ a
答え1
問題は/bin/sh
DebianやUbuntu(dash
)、OpenBSDなどのシステムです。環境から削除%
bashにエクスポートされた関数をエンコードするために使用される文字を含む、名前などの奇妙な文字を含む変数BASH_FUNC_foo%%=() { ...
。
|-
fromopen
関数の後に引数リストではなく単一の引数が続き、その引数にシェルメタ文字(バックスラッシュがその1つ)が含まれている場合、Perlはそれを直接使用するのではなく引数として渡し/bin/sh -c
ます。execvp(2)
Perlの、およびsystem
のような機能にも同様に適用され、 に文書化されています。 exec
open2
perldoc -f system
より簡単な例:
$ foo(){ echo foo; }; export -f foo
$ perl -e 'system shift' '/bin/bash -c foo\ a'
/bin/bash: foo: command not found
$ perl -e 'system shift' '/bin/bash -c foo'
foo
$ perl -e 'system shift' '/bin/bash -c "foo"'
/bin/bash: foo: command not found
$ perl -e 'open F, "|-", shift' '/bin/bash -c foo\ a'
/bin/bash: foo: command not found
$ perl -e 'open F, "|-", shift' '/bin/bash -c foo'
foo
回避策は、ユーザーのコマンドを使用して外部コマンドを実行することです$ENV{SHELL}
。これにより、すべてのシェル機能をシームレスに使用できます。
perl -e 'open F, "|-", $ENV{SHELL}, "-c", "@ARGV"' '/bin/bash -c "foo a"'
答え2
システム間でエクスポートされたbash機能の移植性に問題があります。はい、そうですね。
簡単に携帯性を向上させます。
$ touch myfunc
$ chmod a+x myfunc
#! /usr/bin/env bash
そして、shebang行から始めて、必要なbashコードをファイルに入れます。 (env
服従$PATH
してください。)
次に、バリアントがどのように振る舞うのか、それに準拠しているのではなく、sh
プログラム(gnu並列を含む)のフォーク+実行機能に依存します。dash
bash