为什么论据中间存在一个EOF?


20

我想编写一个小的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。

Answers:


42

这个Stack Overflow答案中的表(从Bash Hackers Wiki获得)解释了如何扩展不同的Bash变量:

您正在做python -i -c "from $@",变成python -i -c "from sys" "import" "stdout",并且-c只接受一个参数,因此它正在运行command from sys。您要使用$*,它将扩展为python -i -c "from sys import stdout"(假设$IFS未设置或以空格开头)。


2
谢谢您取消删除,因为这是有价值的信息:)
cat

1
我认为这应该是可以接受的答案,因为这实际上可以解决问题,另一位赞成的人只是解释了问题,但未提供解决方案或替代解决方法
Ferrybig

好答案。该表实际上来自Bash Hackers Wiki。您能否添加适当的归属并验证您是否有权发布?
与莫妮卡(Monica)进行的轻度比赛

22

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$ 

然后回到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导致的。


9

$@用双引号将其扩展为元素列表"$1" "$2" "$3"等。

#!/bin/bash
expand () {
    for string in "from $@" ; do
        echo "$string"
    done
}

expand sys import stdout

Python期望代码位于一个参数中,而不是一系列参数中。


6

Python被作为

execve("/usr/bin/python", ["python", "-i", "-c", "from sys", "import", "stdout"], [/* 54 vars */])

(请参阅thrig的答案)。

要将其$@扩展为单个字符串(假设为sane $IFS),可以$*在双引号内使用:

python3 -i -c "from $*"

确认strace -e execve

execve("/usr/bin/python", ["python", "-i", "-c", "from sys import stdout"], [/* 54 vars */]) = 0

2

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”上起作用。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.