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

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

我想编写一个小 bash 函数,以便我可以告诉 bash,import os或者from sys import stdout它会生成一个新的 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。流末尾有一个换行符,这是预料之中的。

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

该表在这个堆栈溢出答案(这是从Bash 黑客维基) 解释了如何扩展不同的 Bash 变量:

你正在做python -i -c "from $@",它变成python -i -c "from sys" "import" "stdout",并且-c只接受一个参数,所以它正在运行命令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

回到第一个 shell:

bash-4.1$ from sys import stdout
  File "<string>", line 1
    from sys
           ^
SyntaxError: invalid syntax
>>> 
bash-4.1$ 

然后回到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

因此,实际的-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 期望代码位于一个参数中,而不是一系列参数中。

答案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”作为一个参数被发送到 python。
这就是 python 接收的内容,并且 python 作用于“from sys”。

相关内容