0

Python (バージョン 2.6.5) コード内からシェル コマンドを実行しようとしていますが、シェル (bash) 内で実行された同じコマンドとは異なる出力が生成されます。

バッシュ:

~> ifconfig eth0 | sed -rn 's/inet addr:(([0-9]{1,3}\.){3}[0-9]{1,3}).*/\1/p' | sed   's/^[ \t]*//;s/[ \t]*$//'
192.168.1.10

パイソン:

>>> def get_ip():
...     cmd_string = "ifconfig eth0 | sed -rn \'s/inet addr:(([0-9]{1,3}\.){3}[0-9]{1,3}).*/\1/p' | sed 's/^[ \t]*//;s/[ \t]*$//\'"
...     process = subprocess.Popen(cmd_string, shell=True, stdout=subprocess.PIPE)
...     out, err = process.communicate()
...     return out
... 
>>> get_ip()
'\x01\n'

私の推測では、Python で実行しているときに何らかの方法で引用符をエスケープする必要があると思いますが、これについてどうすればよいかわかりません。

注: このコードを実行する必要があるマシンに、追加のモジュールをインストールしたり、python を更新したりすることはできません。Python 2.6.5 と標準ライブラリでそのまま動作する必要があります。

4

3 に答える 3

1

コードが機能しない理由は、十分にエスケープしていないためです。引用符をエスケープしましたが、エスケープする必要があるものは他にありません。

意図したコマンド ラインを見てみましょう。

ifconfig eth0 | sed -rn 's/inet addr:(([0-9]{1,3}\.){3}[0-9]{1,3}).*/\1/p' | sed   's/^[ \t]*//;s/[ \t]*$//'

そして、実際のコマンドラインを印刷します(ただprint cmd_string

ifconfig eth0 | sed -rn 's/inet addr:(([0-9]{1,3}\.){3}[0-9]{1,3}).*//p' | sed 's/^[    ]*//;s/[    ]*$//'

明らかに、これらは同じではありません。主な違いは、 your\1が目に見えない制御文字、つまり順序​​が 1 の制御文字 (つまり、ctrl-A) に置き換えられていることです。(それぞれをタブ文字に置き換えまし\tたが、おそらく何も壊れません。)

Printing out the repr of the line (print repr(cmd_string)) often helps as well:

"ifconfig eth0 | sed -rn 's/inet addr:(([0-9]{1,3}\\.){3}[0-9]{1,3}).*/\x01/p' | sed 's/^[ \t]*//;s/[ \t]*$//'"

That \x01 should immediately alert you to what's going on—or, even if you don't understand it, it should alert you to where something is going wrong, so you can do an easier search or write a simpler question at SO.

You should get in the habit of doing both of these whenever you've got something wrong with escaping.


However, usually, the answer is easy: instead of trying to figure out what does and doesn't need to be escaped, just use a raw string:

cmd_string = r"ifconfig eth0 | sed -rn 's/inet addr:(([0-9]{1,3}\.){3}[0-9]{1,3}).*/\1/p' | sed   's/^[ \t]*//;s/[ \t]*$//'"

Now, when you print that out, you get:

ifconfig eth0 | sed -rn 's/inet addr:(([0-9]{1,3}\.){3}[0-9]{1,3}).*/\1/p' | sed   's/^[ \t]*//;s/[ \t]*$//'

Exactly what you wanted.

于 2013-06-24T22:16:59.643 に答える
0

Python では、文字列を二重引用符で囲むと、その文字列内でエスケープする必要なく単一引用符を使用でき、その逆も同様です。ただし、\ プレフィックスを追加してバックスラッシュをエスケープする必要があります。

おそらく、これをデバッグするための最善の策は、次を追加することです。

print cmd_string

cmd_string を設定した直後に、これを元のバージョンと比較して、さらに文字が欠落しているかどうかを確認します (これらもエスケープする必要があります)。

于 2013-06-24T21:55:31.807 に答える