237

Python を使用し-cてワンライナー ループを実行しています。

$ python -c "for r in range(10): print 'rob'"

これはうまくいきます。ただし、for ループの前にモジュールをインポートすると、構文エラーが発生します。

$ python -c "import sys; for r in range(10): print 'rob'"
  File "<string>", line 1
    import sys; for r in range(10): print 'rob'
              ^
SyntaxError: invalid syntax

これを修正する方法はありますか?

Makefile に含めることができるように、これをワンライナーにすることが重要です。

4

18 に答える 18

218

あなたができる

echo -e "import sys\nfor r in range(10): print 'rob'" | python

またはパイプなし:

python -c "exec(\"import sys\nfor r in range(10): print 'rob'\")"

また

(echo "import sys" ; echo "for r in range(10): print 'rob'") | python

または@SilentGhost の回答/ @Crast の回答

于 2010-01-11T17:18:43.587 に答える
107

このスタイルはmakefileでも使用できます(実際、かなり頻繁に使用されます)。

python - <<EOF
import sys
for r in range(3): print 'rob'
EOF

また

python - <<-EOF
    import sys
    for r in range(3): print 'rob'
EOF

後者の場合、先頭のタブ文字も削除されます(そして、いくつかの構造化された見通しを達成することができます)

EOFの代わりに、行頭のヒアドキュメントに表示されないマーカーワードを表すことができます(bashマンページのヒアドキュメントまたはここも参照してください)。

于 2010-03-01T14:38:57.593 に答える
65

問題は実際には import ステートメントではなく、for ループの前にあるものにあります。より具体的には、インライン ブロックの前に表示されるもの。

たとえば、これらはすべて機能します。

python -c "import sys; print 'rob'"
python -c "import sys; sys.stdout.write('rob\n')"

import がステートメントであることが問題である場合、これは機能しますが、機能しません。

python -c "__import__('sys'); for r in range(10): print 'rob'"

非常に基本的な例では、次のように書き直すことができます。

python -c "import sys; map(lambda x: sys.stdout.write('rob%d\n' % x), range(10))"

ただし、ラムダは式のみを実行でき、ステートメントや複数のステートメントは実行できないため、やりたいことを実行できない場合があります。ただし、ジェネレータ式、リスト内包表記、ラムダ、sys.stdout.write、「マップ」ビルトイン、およびいくつかの創造的な文字列補間の間で、いくつかの強力なワンライナーを実行できます。

問題は、どこまで行きたいかということです。また.py、makefile を代わりに実行する小さなファイルを作成した方がよいのはどの時点でしょうか?

于 2010-01-11T17:39:30.960 に答える
32

これを修正する方法はありますか?

あなたの問題は、 で区切られた Python ステートメントは、;すべてワンライナーである「小さなステートメント」にしか許可されないという事実によって作成されます。Python docsの文法ファイルから:

stmt: simple_stmt | compound_stmt
simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
small_stmt: (expr_stmt | del_stmt | pass_stmt | flow_stmt |
             import_stmt | global_stmt | nonlocal_stmt | assert_stmt)

複合ステートメントは、セミコロンを使用して他のステートメントと同じ行に含めることはできません。そのため、フラグを使用してこれを行うと、-c非常に不便になります。

bash シェル環境で Python のデモを行う場合、複合ステートメントを含めると非常に便利です。これを確実に行う唯一の簡単な方法は、ヒアドキュメント (posix シェルのもの) を使用することです。

ヒアドキュメント

ヒアドキュメント( で作成<<) と Python のコマンド ライン インターフェイス オプションを使用し-ます。

$ python - <<-"EOF"
        import sys                    # 1 tab indent
        for r in range(10):           # 1 tab indent
            print('rob')              # 1 tab indent and 4 spaces
EOF

-後に<<( )を追加すると、タブ<<-を使用してインデントできます (Stackoverflow はタブをスペースに変換するため、これを強調するために 8 つのスペースをインデントしました)。先頭のタブが削除されます。

タブなしで次のようにできます<<

$ python - << "EOF"
import sys
for r in range(10):
    print('rob')
EOF

引用符で囲むと、パラメーター算術展開EOFが防止されます。これにより、ヒアドキュメントがより堅牢になります。

複数行の文字列を Bash する

二重引用符を使用すると、シェル拡張が得られます。

$ python -c "
> import sys
> for p in '$PATH'.split(':'):
>     print(p)
> "
/usr/sbin
/usr/bin
/sbin
/bin
...

シェルの展開を避けるには、一重引用符を使用します。

$ python -c '
> import sys
> for p in "$PATH".split(":"):
>     print(p)
> '
$PATH

Python では、リテラルの引用符を交換する必要があることに注意してください。基本的に、BASH によって解釈される引用符は使用できません。ただし、Python でできるように、それらを交互に使用することはできますが、これはすでにかなり混乱しているように見えるため、これをお勧めしません。

$ python -c '
import sys
for p in "'"$PATH"'".split(":"):
    print(p)
'
/usr/sbin
/usr/bin
/sbin
/bin
...

受け入れられた回答(およびその他)の批判

これはあまり読みにくい:

echo -e "import sys\nfor r in range(10): print 'rob'" | python

あまり読みにくく、さらにエラーが発生した場合のデバッグが困難です。

python -c "exec(\"import sys\\nfor r in range(10): print 'rob'\")"

おそらくもう少し読みやすいかもしれませんが、それでもかなり醜いです:

(echo "import sys" ; echo "for r in range(10): print 'rob'") | python

"Python に 's'があると、うまくいきません。

$ python -c "import sys
> for r in range(10): print 'rob'"

mapfor ループを取得するために内包表記を悪用したりリストしたりしないでください。

python -c "import sys; map(lambda x: sys.stdout.write('rob%d\n' % x), range(10))"

これらはすべて悲しくて悪いです。それらをしないでください。

于 2016-07-06T23:56:34.410 に答える
16

return を使用して、次の行に入力します。

user@host:~$ python -c "import sys
> for r in range(10): print 'rob'"
rob
rob
...
于 2010-01-11T17:14:19.760 に答える
11

$ python2.6 -c "import sys; [sys.stdout.write('rob\n') for r in range(10)]"

正常に動作します。for ループをインライン化するには、「[ ]」を使用します。

于 2012-01-11T13:40:49.527 に答える
8

問題はimportステートメントではありません。問題は、制御フロー ステートメントが python コマンドでインライン化されないことです。そのimportステートメントを他のステートメントに置き換えると、同じ問題が発生します。

考えてみてください: Python はおそらくすべてをインライン化することはできません。インデントを使用して制御フローをグループ化します。

于 2010-01-11T17:19:27.240 に答える
7

システムが Posix.2 に準拠している場合、printfユーティリティを提供する必要があります。

$ printf "print 'zap'\nfor r in range(3): print 'rob'" | python
zap
rob
rob
rob
于 2010-01-12T01:33:45.763 に答える
4

single/double quotesそしてbackslashどこでも:

$ python -c 'exec("import sys\nfor i in range(10): print \"bob\"")'

ずっといい:

$ python -c '
> import sys
> for i in range(10):
>   print "bob"
> '
于 2011-12-11T08:17:12.023 に答える
4

(10 年 11 月 23 日 19:48 に回答済み) 私はあまり Python が得意ではありませんが、この構文を一度見つけて、どこから来たのか忘れてしまったので、文書化しようと思いました:

sys.stdout.write代わりにprint(の違いは、sys.stdout.write括弧内に引数を関数として受け取りますが、そうではありprintません) の代わりに使用すると、ワンライナーの場合、コマンドと の順序を逆にしてfor、セミコロンを削除することで回避できます。コマンドを角括弧で囲みます。つまり、次のようになります。

python -c "import sys; [sys.stdout.write('rob\n') for r in range(10)]"

この構文がPythonでどのように呼び出されるかわかりません:)

お役に立てれば、

乾杯!


(EDIT Tue Apr 9 20:57:30 2013)さて、私は最終的にこれらのワンライナーの角括弧が何であるかを見つけたと思います。それらは「リスト内包表記」です(明らかに)。最初に Python 2.7 でこれに注意してください:

$ STR=abc
$ echo $STR | python -c "import sys,re; a=(sys.stdout.write(line) for line in sys.stdin); print a"
<generator object <genexpr> at 0xb771461c>

したがって、丸括弧/括弧内のコマンドは「ジェネレータ オブジェクト」と見なされます。呼び出して「反復」next()すると、括弧内のコマンドが実行されます(出力の「abc」に注意してください):

$ echo $STR | python -c "import sys,re; a=(sys.stdout.write(line) for line in sys.stdin); a.next() ; print a"
abc
<generator object <genexpr> at 0xb777b734>

ここで角括弧を使用すると、コマンドを実行するために呼び出す必要がないことに注意してくださいnext()。割り当て後すぐに実行されます。ただし、後で調べると、次のことaがわかりNoneます。

$ echo $STR | python -c "import sys,re; a=[sys.stdout.write(line) for line in sys.stdin]; print a"
abc
[None]

角括弧の場合、これは探すべき多くの情報を残しません-しかし、私はこのページに出くわしました。

Python のヒントとコツ - 第 1 版 - Python チュートリアル | Dream.In.Code :

思い出すと、単一行ジェネレーターの標準形式は、括弧内の 1 行の「for」ループのようなものです。これにより、「ワンショット」の反復可能なオブジェクトが生成されます。これは、一方向にのみ反復でき、最後に到達すると再利用できないオブジェクトです。

「リスト内包表記」は、通常の角括弧 ( ) が角括弧 [ ] に置き換えられていることを除いて、通常の 1 行ジェネレーターとほとんど同じように見えます。連想リスト内包表記の主な利点は、「1 回限りの」反復可能なオブジェクトではなく「リスト」を生成することです。これにより、前後に移動したり、要素を追加したり、並べ替えたりすることができます。

実際、それはリストです-実行されるとすぐに最初の要素が none になるだけです:

$ echo $STR | python -c "import sys,re; print [sys.stdout.write(line) for line in sys.stdin].__class__"
abc
<type 'list'>
$ echo $STR | python -c "import sys,re; print [sys.stdout.write(line) for line in sys.stdin][0]"
abc
None

リスト内包表記については、5. データ構造: 5.1.4 に記載されています。リスト内包表記 — Python v2.7.4 のドキュメント「リスト内包表記は、リストを作成するための簡潔な方法を提供します」; おそらく、リストの制限された「実行可能性」がワンライナーで機能するのはここです。

まあ、私がここであまりにも的外れでないことを願っています...

EDIT2: これは、ネストされていない 2 つの for ループを含む 1 行のコマンド ラインです。両方とも「リスト内包表記」角括弧で囲まれています。

$ echo $STR | python -c "import sys,re; a=[sys.stdout.write(line) for line in sys.stdin]; b=[sys.stdout.write(str(x)) for x in range(2)] ; print a ; print b"
abc
01[None]
[None, None]

2 番目の「リスト」bには、for ループが明示的に 2 回実行されたため、2 つの要素が含まれていることに注意してください。ただし、sys.stdout.write()両方の場合の結果は (どうやら)Noneでした。

于 2010-11-23T19:48:43.007 に答える
2

このスクリプトは、Perl に似たコマンド ライン インターフェイスを提供します。

Pyliner - コマンドラインで任意の Python コードを実行するスクリプト (Python レシピ)

于 2012-02-16T18:37:15.817 に答える
2

次のプロパティを持つソリューションが必要でした。

  1. 読み取り可能
  2. 他のツールの出力を処理するための stdin の読み取り

両方の要件は他の回答では提供されていないため、コマンドラインですべてを実行しながら標準入力を読み取る方法は次のとおりです。

grep special_string -r | sort | python3 <(cat <<EOF
import sys
for line in sys.stdin:
    tokens = line.split()
    if len(tokens) == 4:
        print("%-45s %7.3f    %s    %s" % (tokens[0], float(tokens[1]), tokens[2], tokens[3]))
EOF
)
于 2018-11-27T18:32:08.803 に答える
1

「python cmdfile.py」を渡したかのように stdin に触れてシミュレートしたくない場合は、bash シェルから次の操作を実行できます。

$ python  <(printf "word=raw_input('Enter word: ')\nimport sys\nfor i in range(5):\n    print(word)")

ご覧のとおり、stdin を使用して入力データを読み取ることができます。内部的に、シェルは入力コマンドの内容の一時ファイルを作成します。

于 2013-01-10T14:06:22.270 に答える
1

これを行う必要があるときは、使用します

python -c "$(echo -e "import sys\nsys.stdout.write('Hello World!\\\n')")"

sys.stdout.write ステートメントの改行の 3 つのバックスラッシュに注意してください。

于 2013-02-14T11:11:33.080 に答える