私はbash、import os
またはfrom sys import stdout
を認識できるように小さなbash関数を書きたかったので、インポートされたモジュールで新しいPythonインタープリターが生成されます。
後者の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を読み取るかのように動作しています。ストリームの最後に改行があり、予想された。
Pythonモジュール全体をインポートするfrom
の姉妹は次のようになり、文字列をサニタイズして処理し、存在しないモジュールで失敗することによって問題を解決します。
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があると考える理由を理解したいと思います。
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
barfsが有効な切り捨てられたコマンドです。
$@
二重引用符で囲むと、要素のリストに展開されます"$1" "$2" "$3"
など.
#!/bin/bash
expand () {
for string in "from $@" ; do
echo "$string"
done
}
expand sys import stdout
Pythonは、コードが一連の引数ではなく、1つの引数にあることを期待します。
Pythonは次のように呼び出されます
execve("/usr/bin/python", ["python", "-i", "-c", "from sys", "import", "stdout"], [/* 54 vars */])
( thrig's answer を参照)。
$@
を単一の文字列として展開するには(正常な$IFS
を想定)、二重引用符内で$*
を使用できます。
python3 -i -c "from $*"
strace -e execve
で確認済み:
execve("/usr/bin/python", ["python", "-i", "-c", "from sys import stdout"], [/* 54 vars */]) = 0
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>
「sysから」がpythonに1つの引数として送信されていることは明らかです。
これがpythonが受け取るものであり、pythonは「sysから」に作用します。