Wykonywanie poleceń Pythona w jednym wierszu poleceń

Używam Pythona z -c do wykonania pętli jednowierszowej, tzn.:

$ python -c "for r in range(10): print 'rob'"
To działa dobrze. Jeśli jednak zaimportuję moduł przed pętlą for, pojawia się błąd składni:
$ 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
Wiesz, jak to naprawić?

Ważne jest dla mnie, aby mieć to jako jednolinijkowy, abym mógł to umieścić w pliku Makefile.

Author: Aaron Hall, 2010-01-11

17 answers

You could do

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

Lub rury w / out:

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

Lub

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

Lub @odpowiedź SilentGhost / @odpowiedź Crasta

 125
Author: jspcal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:44

Ten styl może być również używany w plikach Makefile (i w rzeczywistości jest używany dość często).

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

Lub

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

W drugim przypadku znaki tabulacji są również usuwane (i można uzyskać pewien ustrukturyzowany outlook)

Zamiast EOF może zawierać dowolne słowo znacznikowe, które nie pojawia się w dokumencie here na początku linii (patrz również tutaj dokumenty na stronie podręcznika bash lub tutaj ).

 71
Author: xorho,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-25 01:01:15

Problem nie dotyczy instrukcji import, tylko tego, co znajduje się przed pętlą for. A dokładniej, wszystko, co pojawia się przed wbudowanym blokiem.

Na przykład te wszystkie działają:

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

Jeśli import będący oświadczeniem byłby problemem, to działałoby, ale tak nie jest:

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

Dla twojego bardzo podstawowego przykładu, możesz napisać go od nowa Tak:

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

Jednak lambda może wykonywać tylko wyrażenia, a nie instrukcje lub wiele instrukcji, więc możesz nadal nie możesz robić tego, co chcesz. Natomiast pomiędzy wyrażeniami generatora, list comprehension, lambda, sys.stdout.napisz, wbudowana" mapa " i kilka kreatywnych interpolacji ciągów, możesz zrobić kilka potężnych jednolinijkowych.

Pytanie brzmi, jak daleko chcesz się posunąć i w którym momencie nie lepiej jest napisać mały plik .py, który zamiast tego wykonuje Twój plik makefile?

 38
Author: Crast,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-11 17:39:30


- Aby ta odpowiedź działała z Pythonem 3.x również print jest wywoływana jako funkcja : W 3.x, tylko print('foo') działa, natomiast 2.x akceptuje również print 'foo'.
-Dla perspektywy wieloplatformowej, która obejmuje Windows, zobacz pomocna odpowiedź kxr.

W bash, ksh, lub zsh:

Użyj ANSI C-cytowany ciąg znaków ($'...'), co pozwala używać \n do reprezentowania nowych linii są one rozszerzane do nowych linii przed przekazaniem do python:

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

Zwróć uwagę na \n pomiędzy import i for, aby spowodować przerwanie linii.

Aby przekazać wartości zmiennej powłoki do takiego polecenia, najbezpieczniej jest użyć argumentów i uzyskać do nich dostęp poprzez sys.argv wewnątrz skryptu Pythona:

name='rob' # value to pass to the Python script
python -c $'import sys\nfor r in range(10): print(sys.argv[1])' "$name"

poniżej omówienie zalet i wad użycia (Sekwencja escape-preprocessed) Double-quoted string with embedded Shell-variable references.

Aby bezpiecznie pracować z$'...' ciągami:

  • Double \ instancje w Twoim oryginalnym kodzie źródłowym.
    • \<char> sekwencje - takie jak \n w tym przypadku, ale także zwykłe podejrzane, takie jak \t, \r, \b - są rozszerzane o $'...' (zobacz {[28] } dla obsługiwanych Escape)
  • Escape ' instancje jako \'.

Jeśli musisz pozostać zgodny z POSIX :

Użyj printf Z zastąpienie polecenia :

python -c "$(printf %b 'import sys\nfor r in range(10): print("rob")')"

Aby bezpiecznie pracować z tego typu ciągiem:

  • Double \ instancje w Twoim oryginalnym kodzie źródłowym.
    • \<char> sekwencje - takie jak \n w tym przypadku, ale także zwykłe podejrzane, takie jak \t, \r, \b - są rozszerzone o printf (zobacz man printf dla wspieranego escape sekwencji).
  • Przekaż pojedynczy cytat łańcuch do printf %bi unikaj osadzonych pojedynczych cudzysłowów jako '\'' (sic).

    • Użycie pojedynczych cudzysłowów chroni zawartość łańcucha przed interpretacją przez powłokę .

      • To powiedziawszy, dla krótkich skryptów Pythona (jak w tym przypadku) możesz użyć podwójnego cytowanego ciągu, aby włączyć shell wartości zmiennych do swoich skryptów - tak długo, jak na przykład powłoka rozszerza $HOME do katalogu domowego bieżącego użytkownika. w następującym poleceniu:

        • python -c "$(printf %b "import sys\nfor r in range(10): print('rob is $HOME')")"
      • Jednak ogólnie preferowanym podejściem jest przekazywanie wartości z powłoki przez argumenty , A dostęp do nich przez sys.argv w Pythonie; odpowiednikiem powyższego polecenia jest:

        • python -c "$(printf %b 'import sys\nfor r in range(10): print("rob is " + sys.argv[1])')" "$HOME"
    • Podczas korzystania z double-quoted string jest bardziej wygodny - pozwala na używanie osadzonych pojedynczych cudzysłowów bez znaków i osadzonych podwójnych cudzysłowów jako \" - sprawia również, że łańcuch jest interpretowany przez powłokę , co może, ale nie musi być intencją; $ i ` w kodzie źródłowym, które nie są przeznaczone dla powłoki, może spowodować błąd składni lub nieoczekiwanie zmienić łańcuch.

      • dodatkowo, powłoki własne \ przetwarzanie w na przykład, aby uzyskać Python , aby wytworzyć literalne wyjście ro\b, musisz przekazać ro\\b do niego; z '...' łańcuch powłoki i dwukrotnie \ instancje, otrzymujemy:
        python -c "$(printf %b 'import sys\nprint("ro\\\\bs")')" # ok: 'ro\bs'
        W przeciwieństwie do tego, to Nie działa zgodnie z przeznaczeniem z "..." łańcuchem powłoki:
        python -c "$(printf %b "import sys\nprint('ro\\\\bs')")" # !! INCORRECT: 'rs'
        Powłoka interpretuje zarówno "\b" i "\\b" jako dosłowne \b, wymagające zawrotnej liczby dodatkowych \ instancji, aby osiągnąć pożądany efekt:
        python -c "$(printf %b "import sys\nprint('ro\\\\\\\\bs')")"

Do prześlij Kod przez stdin zamiast -c:

Uwaga: skupiam się na single-line solutions here; odpowiedź xorho pokazuje, jak używać wielowierszowego here-document - pamiętaj, aby cytować ogranicznik, jednak; na przykład, <<'EOF', chyba że wyraźnie chcesz, aby powłoka rozszerzyła łańcuch z przodu (co pochodzi z zastrzeżeniami zauważonymi powyżej).


W bash, ksh, lub zsh:

Połącz ANSI C-cytowany ciąg znaków ($'...') z tutaj-ciąg (<<<...):

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

- mówi python jawnie do odczytu ze standardowego wejścia (co robi domyślnie). - jest opcjonalne w tym przypadku, ale jeśli chcesz również przekazać argumenty do skryptów, musisz rozdzielić argument z nazwy pliku skryptu:

python - 'rob' <<<$'import sys\nfor r in range(10): print(sys.argv[1])'

Jeśli musi pozostać zgodne z POSIX :

Użyj printf jak wyżej, ale z rurociągiem , aby przekazać swoje wyjście przez stdin:

printf %b 'import sys\nfor r in range(10): print("rob")' | python

Z argumentem:

printf %b 'import sys\nfor r in range(10): print(sys.argv[1])' | python - 'rob'
 15
Author: mklement0,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:22

Po prostu użyj return i wpisz go w następnej linii:

user@host:~$ python -c "import sys
> for r in range(10): print 'rob'"
rob
rob
...
 11
Author: SilentGhost,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-11 17:14:19
Wiesz, jak to naprawić?

Twój problem jest spowodowany faktem, że wyrażenia Pythona, oddzielone przez ;, mogą być tylko "małymi wyrażeniami", które są jednowierszowymi. Z pliku gramatyki w 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)

Wyrażenia złożone nie mogą być dołączane do tej samej linii z innymi wyrażeniami za pomocą średników - więc robienie tego ze znacznikiem -c staje się bardzo niewygodne.

Podczas demonstracji Python podczas gdy w środowisku powłoki bash, uważam, że bardzo przydatne jest dołączanie poleceń złożonych. Jedynym prostym sposobem na to jest heredocs.

Heredocs

Użyj heredoc (utworzonego za pomocą <<) i opcji interfejsu linii poleceń Pythona , -:

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

Dodanie - po << (<<-) pozwala na użycie tabulatorów do wcięcia (Stackoverflow konwertuje tabulatory na spacje, więc wciąłem 8 spacji, aby to podkreślić). Na tabulatory wiodące zostaną usunięte.

Możesz to zrobić bez zakładek za pomocą tylko <<:

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

Umieszczenie cudzysłowów wokół EOF zapobiega parametrowi i ekspansji arytmetycznej . To sprawia, że heredoc jest bardziej wytrzymały.

Krytyka zaakceptowanej odpowiedzi (i innych)

To nie jest zbyt czytelne:

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

Niezbyt czytelny, a dodatkowo trudny do debugowania w przypadku błąd:

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

Może trochę bardziej czytelny, ale nadal dość brzydki:

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

Będziesz miał zły czas, jeśli masz " ' s w swoim Pythonie:

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

Nie nadużywaj map ani list składających, aby uzyskać pętle for:

python -c "import sys; map(lambda x: sys.stdout.write('rob%d\n' % x), range(10))"
To wszystko jest smutne i złe. Nie rób tego.
 10
Author: Aaron Hall,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-07 18:20:43

Problem nie dotyczy import stwierdzenia. Problem polega na tym, że polecenia control flow nie działają inline w poleceniu Pythona. Zastąp import instrukcję dowolną inną instrukcją, a zobaczysz ten sam problem.

Pomyśl o tym: python nie może wszystkiego wbudować. Wykorzystuje wcięcia do grupowania przepływu sterowania.

 7
Author: David Berger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-11 17:19:27

Jeśli Twój system jest Posix.2012-01-23 14: 00: 00]}

$ printf "print 'zap'\nfor r in range(3): print 'rob'" | python
zap
rob
rob
rob
 7
Author: Alex Martelli,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-01-12 01:33:45

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

Działa dobrze. Użyj " [ ]", aby wstawić pętlę for.
 7
Author: Pierre Pericard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-01-11 13:40:49

(odpowiedział 23 listopada '10 o 19: 48) Nie jestem naprawdę wielkim Pythonerem - ale znalazłem tę składnię raz, zapomniałem skąd, więc pomyślałem, że to udokumentuję: {]}

Jeśli używasz sys.stdout.write zamiast print (różnica polega na tym, że sys.stdout.write przyjmuje argumenty jako funkcję, w nawiasie - podczas gdy print Nie ), wtedy dla jednowierszowej można odwrócić kolejność polecenia i for, usunąć średnik i zamknąć polecenie w nawiasach kwadratowych, tzn.:

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

Nie mam pojęcia jak ta składnia będzie wywoływana w Pythonie:)

Mam nadzieję, że to pomoże,

Zdrówko!

(EDIT WT Kwi 9 20:57:30 2013) Cóż, myślę, że w końcu odkryłem, o czym są te nawiasy kwadratowe w jednowierszowych; są to" składanie list " (najwyraźniej); najpierw zauważ to w Pythonie 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>

Więc polecenie w nawiasach okrągłych jest postrzegane jako "obiekt generatora"; jeśli "iterujemy" przez niego wywołując next() - następnie zostanie wykonana Komenda wewnątrz nawiasu (zwróć uwagę na " abc " na wyjściu):

$ 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>

Jeśli teraz używamy nawiasów kwadratowych-zauważ, że nie musimy wywoływać next(), aby polecenie Wykonało się natychmiast po przypisaniu; jednak późniejsza inspekcja ujawnia, że a to None:

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

To nie pozostawia wiele informacji do szukania, dla przypadku nawiasów kwadratowych - ale natknąłem się na tę stronę, która myślę, że wyjaśnia: {]}

Porady I Triki Pythona – Pierwsze Wydanie - Python Tutorials / Dream.In. Code:

Jeśli pamiętasz, standardowy format generatora jednowierszowego jest rodzajem pętli jednowierszowej " for " wewnątrz nawiasów. Spowoduje to powstanie "jednorazowego" obiektu iterowalnego, który jest obiektem, który można iterować tylko w jednym kierunku i którego nie można ponownie użyć po dotarciu do końca.

'rozumienie listy' wygląda prawie tak samo jak zwykły generator jednowierszowy, z tą różnicą, że zwykłe nawiasy - () - są zastępowane w nawiasach kwadratowych - []. Główną zaletą rozumienia jest to, że tworzy "listę", a nie "jednorazowy" obiekt iteracyjny, dzięki czemu można go przeglądać, dodawać elementy, sortować itp.

W rzeczywistości jest to lista-po prostu jej pierwszy element staje się none, gdy tylko zostanie wykonany:]}
$ 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

Zestawienie List jest inaczej udokumentowane w 5. Struktury Danych: 5.1.4. Składanie List-Python v2.7.4 documentation as " lista składanie zapewnia zwięzły sposób tworzenia list"; prawdopodobnie w tym miejscu pojawia się ograniczona "wykonalność" list w jednolinijkach.

Cóż, mam nadzieję, że nie jestem zbytnio poza tym znamieniem ...

EDIT2: a oto jednoliniowa linia poleceń z dwoma Nie zagnieżdżonymi pętlami for; obie zamknięte w kwadratowych nawiasach "rozumienie listy":

$ 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]

Zauważ, że druga " lista "b ma teraz dwa elementy, ponieważ jej pętla for przebiegała wyraźnie dwukrotnie; jednak wynik sys.stdout.write() w obu przypadkach był (najwyraźniej) None.

 4
Author: sdaau,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-09 19:32:39

Ten wariant jest najbardziej przenośny do umieszczania skryptów wielowierszowych w wierszu poleceń w systemach Windows i * Nix, py2/3, bez pipes:

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

(żaden z innych przykładów tutaj do tej pory tak nie zrobił)

Schludny w Windows To:

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

Neat on bash / * nix is:

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

Ta funkcja zamienia dowolny skrypt wielowierszowy w przenośny command-one-liner:

def py2cmdline(script):
    exs = 'exec(%r)' % re.sub('\r\n|\r', '\n', script.rstrip())
    print('python -c "%s"' % exs.replace('"', r'\"'))

Użycie:

>>> py2cmdline(getcliptext())
python -c "exec('print \'AA\tA\'\ntry:\n for i in 1, 2, 3:\n  print i / 0\nexcept:\n print \"\"\"longer\nmessage\"\"\"')"

Wejście było:

print 'AA   A'
try:
 for i in 1, 2, 3:
  print i / 0
except:
 print """longer
message"""
 3
Author: kxr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-26 15:11:16

single/double quotes i backslash wszędzie:

$ python -c 'exec("import sys\nfor i in range(10): print \"bob\"")'
Znacznie lepiej:
$ python -c '
> import sys
> for i in range(10):
>   print "bob"
> '
 2
Author: kev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-11 08:17:12

Ten skrypt udostępnia interfejs wiersza poleceń podobny do Perla:

Pyliner-skrypt do uruchamiania dowolnego kodu Pythona w wierszu poleceń (przepis Pythona)

 2
Author: Drew Gulino,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-10-29 11:05:08

Jest jeszcze jedna opcja, sys.stdout.write zwraca None, co powoduje, że lista jest pusta

cat somefile.log|python -c "import sys;[line for line in sys.stdin if sys.stdout.write(line*2)]"
 0
Author: user993533,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-06 04:30:59

Napisałem do tego prostą stronę internetową. Możesz tam wkleić kod wielowierszowy i przekształcić go w działającą instrukcję jednowierszową.

Python Single Line Converter

 0
Author: jagttt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-10 15:58:31

Jeśli nie chcesz dotykać stdin i symulować tak, jakbyś przeszedł "python cmdfile.py", możesz wykonać następujące czynności z powłoki bash:

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

Jak widać, pozwala na używanie stdin do odczytu danych wejściowych. Wewnętrznie powłoka tworzy plik tymczasowy dla zawartości polecenia input.

 0
Author: Thava,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-07 18:24:46

Kiedy musiałem to zrobić, używam

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

Zwróć uwagę na potrójny ukośnik wsteczny dla nowej linii w sys.stdout.napisz oświadczenie.

 0
Author: Devilholk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-07 18:25:25