
私は、bash に指示して、モジュールがインポートされた新しい Python インタープリターを生成するような小さな bash 関数を書きたかったのimport os
ですfrom sys import stdout
。
後者のfrom
関数は次のようになります。
from () {
echo "from $@" | xxd
python3 -i -c "from $@"
}
これを呼び出した場合:
$ from sys import stdout
00000000: 6672 6f6d 2073 7973 2069 6d70 6f72 7420 from sys import
00000010: 7374 646f 7574 0a stdout.
File "<string>", line 1
from sys
^
SyntaxError: invalid syntax
>>>
バイトfrom sys
は
66 72 6f 6d 20 73 79 73 20
f r o m s y s
そこには EOF はありませんが、Python インタープリターは EOF を読み取ったかのように動作します。ストリームの最後には改行がありますが、これは予想どおりです。
from
の姉妹版で、Python モジュール全体をインポートするものは次のようになります。これは、文字列をサニタイズして処理し、存在しないモジュールでは失敗することで問題を解決します。
import () {
ARGS=$@
ARGS=$(python3 -c "import re;print(', '.join(re.findall(r'([\w]+)[\s|,]*', '$ARGS')))")
echo -ne '\0x04' | python3 -i
python3 -c "import $ARGS" &> /dev/null
if [ $? != 0 ]; then
echo "sorry, junk module in list"
else
echo "imported $ARGS"
python3 -i -c "import $ARGS"
fi
}
これにより、ストリーム内の説明されていない EOF の問題は解決されますが、Python が EOF があると判断する理由を理解したいと思います。
答え1
テーブルこのStack Overflowの回答(これはBash ハッカー Wiki) は、さまざまな Bash 変数がどのように展開されるかを説明しています。
を実行していますpython -i -c "from $@"
が、これは に変換されpython -i -c "from sys" "import" "stdout"
、-c
引数を 1 つだけ取るため、コマンド が実行されていますfrom sys
。 を使用する必要がありますが$*
、これは に展開されますpython -i -c "from sys import stdout"
($IFS
が設定されていないか、スペースで始まっていると想定)。
答え2
strace
いつものように、何が起こっているのかを示します。
bash-4.1$ echo $$
3458
strace bash ...
また、他の場所では(または関数呼び出しの方法を理解することもできます):
bash-4.1$ strace -ff -o blah -p 3458
そして最初のシェルに戻ります:
bash-4.1$ from sys import stdout
File "<string>", line 1
from sys
^
SyntaxError: invalid syntax
>>>
bash-4.1$
そしてstrace
シェルに戻ります:
Process 3458 attached
Process 25224 attached
^CProcess 3458 detached
bash-4.1$ grep exec blah.*
blah.25224:execve("/usr/bin/python", ["python", "-i", "-c", "from sys", "import", "stdout"], [/* 54 vars */]) = 0
したがって、実際の-c
引数は、展開された方法、または切り捨てられたコマンド-c "from sys"
によって発生します。"$@"
python
答え3
$@
二重引用符で囲むと、要素のリスト"$1" "$2" "$3"
などに展開されます。
#!/bin/bash
expand () {
for string in "from $@" ; do
echo "$string"
done
}
expand sys import stdout
Python では、コードが一連の引数ではなく 1 つの引数で指定されることを想定しています。
答え4
Strace は、使用されている引数を表示します。ただし、処理されている内容を確認する最も簡単な方法は、printf '<%s> '
関連する各行の前に を追加し、閉じるecho
(新しい行として生成するため) ことです。
したがって、関数は次のように変更できます。
from () {
printf '<%s> ' "from $@"; echo
printf '<%s> ' python3 -i -c "from $@"; echo
}
そして呼び出されたとき:
$ from sys import stdout
<from sys> <import> <stdout>
<python3> <-i> <-c> <from sys> <import> <stdout>
「from sys」が 1 つの引数として Python に送信されていることは明らかです。
これが Python が受信するもので、Python は「from sys」に基づいて動作します。