web-dev-qa-db-ja.com

Python subprocess.call a bash alias

職場では、完了したタスクを一覧表示するスクリプトがあります。これは他の誰かによって書かれ、ネットワーク上でホストされています。私の.bashrcには、このスクリプトを呼び出すエイリアスがあり、多くのフラグなどが付いています。pythonスクリプトを数分ごとに呼び出すスクリプトを作成して、更新された統計でシェルが開きます。ただし、subprocess.call("myAlias")は失敗します。私はまだPythonにかなり慣れていないため、これを理解するのに苦労しています。

from subprocess import call

def callAlias():
    call("myAlias")

callAlias()

私はそれをさらに追加する予定ですが、私は最初のステップで障害にぶつかりました。 :P

私はもっ​​と投稿しますが、注意しなければならない機密情報がたくさんあります。あいまいなコードとエラー出力の欠如について申し訳ありません。

20
jtsmith1287

必要なエイリアスが〜/ .bashrcで定義されている場合、いくつかの理由で実行されません。

1)「シェル」キーワードargを指定する必要があります。

subprocess.call('command', Shell=True)

それ以外の場合、指定されたコマンドは、シェルに渡されるのではなく、実行可能ファイルを見つけるために使用されます。エイリアスや関数などを展開するのはシェルです。

2)デフォルトでは、subprocess.callとその仲間は '/ bin/sh'シェルを使用します。これが呼び出したいBashエイリアスである場合は、サブプロセスに 'executable'キーワード引数を使用して、shではなくbashを使用するように指示する必要があります。

subprocess.call('command', Shell=True, executable='/bin/bash')

3)ただし、/ bin/bashは、「インタラクティブ」シェル(「-i」を使用)として開始しない限り、〜/ .bashrcをソースしません。残念ながら、executable = '/ bin/bash-i'を次のように渡すことはできません。値全体が実行可能ファイルの名前であると見なします。したがって、エイリアスがユーザーの通常のインタラクティブなスタートアップで定義されている場合、 .bashrcでは、次の代替形式を使用してコマンドを呼び出す必要があります。

subprocess.call(['/bin/bash', '-i', '-c', command])
# i.e. Shell=False (the default)
59

ShellキーワードをTrueに設定する必要があります。

call("myAlias", Shell=True)

関連ドキュメント から:

ShellTrueの場合、指定されたコマンドはシェルを介して実行されます。これは、Pythonを主に、ほとんどのシステムシェルで提供される拡張制御フローに使用していて、ファイル名ワイルドカード、シェルパイプ、環境変数拡張などの他のシェル機能にアクセスしたい場合に役立ちます。

エイリアスはシェル機能です(たとえば、エイリアスはシェルによって定義および解釈されます)。

ただし、シェル(/ bin/sh)は非対話的に実行されるため、.profileまたは.bashrcファイルは読み取られず、エイリアスはおそらく使用できません。

完全に拡張されたコマンドをpythonスクリプトで使用することに抵抗がある場合は、 $ENV環境変数 を使用する必要があります。とにかく、シェルにエイリアスが定義されたファイルを読み込ませるには:

call("myAlias", Shell=True, env=dict(ENV='/path/to/aliasfile'))
20
Martijn Pieters

推奨される解決策は、インタラクティブな使用のために排他的にではない機能を定義するためのエイリアスを使用しないことです(それでも、シェル関数は多くの点で優れています)。

エイリアスをスタンドアロンスクリプトにリファクタリングし、他の外部コマンドと同じように呼び出します。

より詳細には、

alias myalias='for x in foo bar baz; do
    frobnicate "$x"; done'

あなたはそれを関数に変えることによってあなたのグローバルな名前空間を汚染しないようにそれを改善することができます

myalias () {
    local x
    for x in foo bar baz; do
        frobnicate "$x"
    done
}

または、/usr/local/bin/myaliasおよびchmod a+x /usr/local/bin/myaliasとして保存して、すべてのユーザーが実行できるようにします。

#!/bin/sh
for x in foo bar baz; do
    frobnicate "$x"
done

(これはサブプロセスで実行されるので、スクリプトが終了するとxはなくなります。そのため、localにする必要はありません。)

(もちろん、frobnicateが完全に適切に記述されている場合は、frobnicate foo bar bazだけに簡略化できるかもしれません。)

これは一般的なFAQです。

5
tripleee

この動作をするために、ジョナサンの理由#2を少し変更しました。作る /usr/local/bin/interactive_bashを含むファイル

#!/bin/bash
/bin/bash -i "$@"

およびchmod +x それ。次にPythonから呼び出すことができます

subprocess.call('my_alias', Shell=True, executable='/usr/local/bin/interactive_bash')
2
James