为什么在参数中间有一个 EOF?

cat*_*cat 20 bash python

我想编写一个小 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未设置或以空格开头)。

  • 感谢您取消删除,因为这是有价值的信息:) (2认同)

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)

然后回到straceshell:

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


cho*_*oba 9

$@在双引号中扩展为元素列表"$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 期望代码在一个参数中,而不是一系列参数中。


Tob*_*ght 6

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)