我想编写一个小 bash 函数,以便我可以告诉 bash,import os
或者from sys import stdout
它会生成一个新的 Python 解释器,并导入模块。
后一个from
函数如下所示:
from () {
echo "from $@" | xxd
python3 -i -c "from $@"
}
Run Code Online (Sandbox Code Playgroud)
如果我这样称呼:
$ 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
>>>
Run Code Online (Sandbox Code Playgroud)
中的字节from sys
是
66 72 6f 6d 20 73 79 73 20
f r o m s y s
Run Code Online (Sandbox Code Playgroud)
那里没有 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
}
Run Code Online (Sandbox Code Playgroud)
这解决了流中无法解释的 EOF 的问题,但我想了解为什么 Python 认为存在 EOF。
Mic*_*zek 42
这个 Stack Overflow 答案中的表格(从Bash Hackers Wiki 得到)解释了不同的 Bash 变量是如何扩展的:
你正在做python -i -c "from $@"
,它变成python -i -c "from sys" "import" "stdout"
,并且-c
只接受一个参数,所以它正在运行命令from sys
。您想使用$*
,它将扩展为python -i -c "from sys import stdout"
(假设$IFS
未设置或以空格开头)。
thr*_*rig 22
strace
,一如既往,将显示正在发生的事情:
bash-4.1$ echo $$
3458
Run Code Online (Sandbox Code Playgroud)
而且,在其他地方(或者您可以弄清楚如何strace bash ...
调用函数):
bash-4.1$ strace -ff -o blah -p 3458
Run Code Online (Sandbox Code Playgroud)
回到第一个 shell:
bash-4.1$ from sys import stdout
File "<string>", line 1
from sys
^
SyntaxError: invalid syntax
>>>
bash-4.1$
Run Code Online (Sandbox Code Playgroud)
然后回到strace
shell:
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
Run Code Online (Sandbox Code Playgroud)
因此,实际-c
参数是-c "from sys"
因为如何"$@"
扩展,或者是一个被截断的命令python
。
$@
在双引号中扩展为元素列表"$1" "$2" "$3"
等。
#!/bin/bash
expand () {
for string in "from $@" ; do
echo "$string"
done
}
expand sys import stdout
Run Code Online (Sandbox Code Playgroud)
Python 期望代码在一个参数中,而不是一系列参数中。
Python 被调用为
execve("/usr/bin/python", ["python", "-i", "-c", "from sys", "import", "stdout"], [/* 54 vars */])
Run Code Online (Sandbox Code Playgroud)
(见thrig 的回答)。
要$@
扩展为单个字符串(假设 sane $IFS
),您可以$*
在双引号内使用:
python3 -i -c "from $*"
Run Code Online (Sandbox Code Playgroud)
确认strace -e execve
:
execve("/usr/bin/python", ["python", "-i", "-c", "from sys import stdout"], [/* 54 vars */]) = 0
Run Code Online (Sandbox Code Playgroud)