為什麼參數中間有一個 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」。

相關內容