引数の途中にEOFがあるのはなぜですか?


20

bashを伝えることができるように、import osまたはfrom sys import stdoutインポートされたモジュールで新しいPythonインタープリターを生成するような小さなbash関数を作成したかったのです。

後者の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を読み取るかのように動作しています。ストリームの最後に改行がありますが、これは予想されることです。

fromPythonモジュール全体をインポートするの姉妹は次のようになり、文字列をサニタイズして処理し、存在しないモジュールで失敗することで問題を解決します。

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があると考える理由を理解したいと思います。

回答:


42

内のテーブルこのスタックオーバーフローの答え(からそれを得たバッシュハッカーのWikiは)異なるバッシュ変数が展開されている方法について説明します。

あなたはやっているpython -i -c "from $@"に変わるいる、python -i -c "from sys" "import" "stdout"-cそれはコマンドを実行しているので、ただ一つの引数を取りますfrom sys。を使用します$*。これは、展開されますpython -i -c "from sys import stdout"$IFS設定されていないか、スペースで始まると仮定します)。


2
これは貴重な情報であるため、削除を削除していただきありがとうございます:)
cat

1
これは実際に問題を解決するため、これは受け入れられた答えだと思います。他の賛成の人は問題を説明するだけですが、解決策や代替回避策を提供しません
-Ferrybig

いい答えだ。このテーブルは、実際にはBash Hackers Wikiからのものです。適切な帰属を追加して、配布する権利があることを確認できますか?
モニカとの軽さのレース

22

strace、いつものように、何が起こっているかを示します:

bash-4.1$ echo $$
3458

そして、他の場所(またはstrace bash ...関数呼び出しの方法を理解できます):

bash-4.1$ strace -ff -o blah -p 3458

そして最初のシェルに戻ります:

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""$@"展開方法、またはpythonbarfsで切り捨てられたコマンドによるものです。


9

$@二重引用符で囲むと、要素のリスト"$1" "$2" "$3"などに展開されます。

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

expand sys import stdout

Pythonは、コードが一連の引数ではなく1つの引数にあることを想定しています。


6

Pythonは次のように呼び出されています

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

thrigの答えを参照)。

取得するには$@(正気を想定した1つの文字列として展開さ$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> '関連する各行の前にaを追加し、終了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」が1つの引数としてpythonに送信されていることは明らかです。
それはpythonが受け取るものであり、pythonは「from sys」で動作します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.