Wykonywanie instrukcji wieloliniowych w jednowierszowym wierszu poleceń?

197

Używam Pythona -cdo wykonania pętli jednowierszowej, tj .:

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

To działa dobrze. Jeśli jednak zaimportuję moduł przed pętlą for, pojawi się błąd składniowy:

$ 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

Masz pomysł, jak to naprawić?

Ważne jest dla mnie, aby mieć to jako jednowierszowe, aby móc dołączyć to do pliku Makefile.

martineau
źródło
Czy to odpowiada na twoje pytanie? Korzystanie ze słownika w celu wybrania funkcji do wykonania
pfabri

Odpowiedzi:

182

mógłbyś

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

lub bez rur:

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ź @ Crast

jspcal
źródło
Ostatnia opcja działa świetnie z python3 w systemie Windows
Ian Ellis
1
@ RudolfOlah mam nadzieję, że już go znasz, ale tylko w celach informacyjnych, musisz zawinąć instrukcję print dla wersji python3 +, takich jak:python -c "exec(\"import sys\nfor r in range(10): print('rob')\")"
systrigger
@systrigger dzięki, brakowało mi, że myślę, że się spieszyłem i nie zdawałem sobie sprawy, że heh
89

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 tym drugim przypadku usuwane są również wiodące znaki tabulatorów (można uzyskać pewne ustrukturyzowane perspektywy)

zamiast EOF może znieść dowolne słowo znacznikowe, które nie pojawia się w dokumencie tutaj na początku wiersza (patrz także tutaj dokumenty na stronie podręcznika bash lub tutaj ).

Xorho
źródło
9
Miły. Aby przekazać argumenty , po prostu umieść je po <<EOF. Zauważ jednak, że lepiej cytować separator - np. <<'EOF'- aby zabezpieczyć zawartość tego dokumentu przed rozszerzeniem powłoki z góry .
mklement0
56

Problem nie dotyczy tak naprawdę instrukcji importu, ale wszystko, co dzieje się przed pętlą for. A dokładniej, wszystko pojawiające się przed wstawionym blokiem.

Na przykład wszystkie działają:

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

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

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

W bardzo prostym przykładzie możesz przepisać go w następujący sposób:

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

Jednak lambdas mogą wykonywać tylko wyrażenia, a nie instrukcje lub wiele instrukcji, więc nadal możesz nie być w stanie zrobić tego, co chcesz. Jednak między wyrażeniami generatora, zrozumieniem listy, lambdami, sys.stdout.write, wbudowanym „mapem” i pewną kreatywną interpolacją ciągów znaków, możesz zrobić potężne jednowierszowe.

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

Crast
źródło
31


- Aby ta odpowiedź działała również w Pythonie 3.x , printjest wywoływana jako funkcja : w 3.x działa tylko print('foo') , a 2.x również akceptuje print 'foo'.
- Aby zapoznać się z perspektywą obejmującą wiele platform, która obejmuje system Windows , zobacz pomocną odpowiedź kxr .

W bash, kshlubzsh :

Użyj ciągu ANSI C ( $'...'), który pozwala \nreprezentować znaki nowej linii, które są rozwijane do rzeczywistych linii przed przekazaniem ciągu do python:

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

Zwróć uwagę na instrukcje \nmiędzy importi for, aby dokonać podziału linii.

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

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 znajduje się omówienie zalet i wad używania podwójnie cytowanego ciągu komend (ucieczka wstępnie przetworzona) z osadzonymi odwołaniami do zmiennych powłoki.

Aby bezpiecznie pracować z $'...'łańcuchami:

  • Podwójne \ wystąpienia w oryginalnym kodzie źródłowym.
    • \<char>Sekwencje - jak \nw tym przypadku, ale również zwykłe podejrzanych, takie jak \t, \r, \b- spienia poprzez $'...'(patrz man printfdla obsługiwanych sekwencji)
  • 'Instancje ucieczki jak \'.

Jeśli musisz pozostać zgodny z POSIX :

Użyj printfz podstawieniem polecenia :

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

Aby bezpiecznie pracować z tego typu ciągiem:

  • Podwójne \ wystąpienia w oryginalnym kodzie źródłowym.
    • \<char>Sekwencje - jak \nw tym przypadku, ale również zwykłe podejrzanych, takie jak \t, \r, \b- są rozszerzane przez printf(patrz man printfdla obsługiwanych sekwencje).
  • Przekaż pojedynczy ciąg znaków 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, w przypadku krótkich skryptów Pythona (jak w tym przypadku) możesz użyć podwójnego cudzysłowu, aby włączyć wartości zmiennych powłoki do swoich skryptów - o ile masz świadomość powiązanych pułapek (patrz następny punkt); np. powłoka rozwija się $HOMEdo 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 za pomocą argumentów i dostęp do nich za pośrednictwem sys.argvPythona; odpowiednikiem powyższego polecenia jest:

        • python -c "$(printf %b 'import sys\nfor r in range(10): print("rob is " + sys.argv[1])')" "$HOME"
    • Korzystanie z ciągu podwójnego cudzysłowu jest wygodniejsze - pozwala na użycie osadzonych pojedynczych cudzysłowów bez ucieczki i osadzonych podwójnych cudzysłowów, ponieważ \"- powoduje również, że ciąg podlega interpretacji przez powłokę , co może, ale nie musi, być intencją; $a `znaki w kodzie źródłowym, które nie są przeznaczone dla powłoki, mogą powodować błąd składniowy lub nieoczekiwanie zmieniać ciąg.

      • Dodatkowo \przeszkadza własne przetwarzanie powłoki w łańcuchach cudzysłowów; na przykład, aby Python wygenerował dosłowny wynik ro\b, musisz go przekazać ro\\b; z '...'ciągiem powłoki i podwójnymi \ instancjami 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 "..."ciągiem powłoki:
        python -c "$(printf %b "import sys\nprint('ro\\\\bs')")" # !! INCORRECT: 'rs'
        Powłoka interpretuje zarówno "\b" i "\\b"dosłownie \b, wymagając oszałamiającej liczby dodatkowych \instancji, aby osiągnąć pożądany efekt:
        python -c "$(printf %b "import sys\nprint('ro\\\\\\\\bs')")"

Aby przekazać kodstdin zamiast -c:

Uwaga: skupiam się tutaj na rozwiązaniach jednowierszowych ; Odpowiedź xorho za pokazuje, jak używać multi-line, tu-dokumentu - pamiętaj, aby zacytować separator jednak; np. <<'EOF'chyba, że ​​wyraźnie chcesz, aby powłoka rozszerzyła łańcuch z przodu (co jest objęte zastrzeżeniami wymienionymi powyżej).


W bash, kshlubzsh :

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

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

-mówi pythonjawnie czytać ze standardowego wejścia (co robi domyślnie). -jest w tym przypadku opcjonalny, ale jeśli chcesz również przekazać argumenty do skryptów, potrzebujesz go, aby ujednoznacznić argument z nazwy pliku skryptu:

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

Jeśli musisz pozostać zgodny z POSIX :

Użyj printfjak wyżej, ale z potokiem , aby przekazać dane wyjściowe 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'
mklement0
źródło
2
To powinna być wybrana odpowiedź!
debiut
1
To również działa i jest prawdopodobnie najlepszą odpowiedzią, ponieważ zawiera pełne wyjaśnienie, brawo!
22

Masz pomysł, jak to naprawić?

Twój problem wynika z faktu, że oddzielone przez Python instrukcje ;mogą być tylko „małymi instrukcjami”, które są jednowierszowe. Z pliku gramatyki w dokumentach Pythona :

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)

Instrukcje złożone nie mogą być zawarte w tym samym wierszu z innymi instrukcjami za pomocą średników - dlatego robienie tego z -cflagą staje się bardzo niewygodne.

Podczas demonstrowania Pythona w środowisku powłoki bash bardzo przydatne jest dołączanie instrukcji złożonych. Jedynym prostym sposobem na niezawodne wykonanie tego jest użycie heredoków (rzecz powłoki posix).

Heredocs

Użyj heredoc (utworzone <<) i Pythona opcji interfejsu wiersza poleceń , -:

$ 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 następującego -po <<(the <<-) pozwala używać tabulatorów do wcięcia (Stackoverflow konwertuje tabulatory na spacje, więc wciąłem 8 spacji, aby to podkreślić). Wiodące zakładki zostaną usunięte.

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

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

Umieszczanie cudzysłowów EOFzapobiega rozszerzaniu parametrów i arytmetyki . Dzięki temu heredoc jest bardziej wytrzymały.

Bash ciągi wieloliniowe

Jeśli użyjesz podwójnego cudzysłowu, otrzymasz rozszerzenie powłoki:

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

Aby uniknąć rozszerzenia powłoki, użyj cudzysłowów:

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

Zauważ, że w Pythonie musimy zamienić znaki cudzysłowu na literały - w zasadzie nie możemy używać znaku cudzysłowu interpretowanego przez BASH. Możemy je zamieniać, tak jak w Pythonie - ale to już wygląda dość mylące, dlatego nie polecam tego:

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

Krytyka zaakceptowanej odpowiedzi (i innych)

Nie jest to zbyt czytelne:

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

Niezbyt czytelny i dodatkowo trudny do debugowania w przypadku błędu:

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

Być może nieco bardziej czytelny, ale wciąż dość brzydki:

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

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

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

Nie nadużywaj mapani nie wymieniaj wyrażeń w celu uzyskania pętli for:

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

Wszystkie są smutne i złe. Nie rób ich.

Aaron Hall
źródło
3
++ dla informacji gramatycznych; (nierozwijający się) tutaj-doc jest poręcznym i najsolidniejszym rozwiązaniem, ale oczywiście nie jest jednostronny. Jeśli rozwiązanie pojedyncza linia jest koniecznością, używając ANSI C-cudzysłowie ( bash, kshlub zsh) jest rozsądne rozwiązanie: python -c $'import sys\nfor r in range(10): print(\'rob\')'(musisz się martwić tylko o ucieczce, apostrofów (których można uniknąć za pomocą cudzysłowów) i ukośniki odwrotne).
mklement0
14

po prostu użyj return i wpisz go w następnym wierszu:

user@host:~$ python -c "import sys
> for r in range(10): print 'rob'"
rob
rob
...
SilentGhost
źródło
6
Poważnie, skręcisz coś, jeśli będziesz to robić dalej. python $(srcdir)/myscript.pydla wielkiej sprawiedliwości.
Jason Orendorff,
10

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

Działa w porządku. Użyj „[]”, aby wstawić pętlę for.

Pierre Pericard
źródło
9

Problem nie dotyczy importoświadczenia. Problem polega na tym, że instrukcje przepływu sterowania nie działają wbudowane w komendzie python. Zastąp to importoświadczenie innym oświadczeniem, a zobaczysz ten sam problem.

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

David Berger
źródło
7

Jeśli twój system jest zgodny z Posix.2, powinien dostarczyć printfnarzędzie:

$ printf "print 'zap'\nfor r in range(3): print 'rob'" | python
zap
rob
rob
rob
Alex Martelli
źródło
2
Dobre rozwiązanie, ale sugeruję użycie w printf %b '...' | pythoncelu zwiększenia niezawodności, ponieważ zapobiega printfinterpretacji sekwencji takich jak %d(specyfikatory formatu) w ciągu wejściowym. Ponadto, chyba że wyraźnie chcesz zastosować rozszerzenia powłoki do łańcucha poleceń Pythona z góry (co może być mylące), lepiej użyć '(pojedynczych cudzysłowów) do zewnętrznego cytowania, aby uniknąć zarówno rozszerzeń, jak i przetwarzania luzu, które stosuje powłoka do łańcuchów cudzysłowów.
mklement0
5

single/double quotesi backslashwszędzie:

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

Dużo lepiej:

$ python -c '
> import sys
> for i in range(10):
>   print "bob"
> '
kev
źródło
więc. wiele. lepszy.
Marc
4

(odpowiedział 23 listopada 2010 o 19:48) Nie jestem naprawdę wielkim Pythonem - ale raz znalazłem tę składnię, zapomniałem skąd, więc pomyślałem, że ją udokumentuję:

jeśli użyjesz sys.stdout.writezamiast print( różnica polega na tym, że sys.stdout.writeprzyjmuje argumenty jako funkcję, w nawiasach - podczas printgdy nie ), to w przypadku jednowierszowego można uniknąć odwrócenia kolejności polecenia i forusunięcia średnika, i zawarcie polecenia w nawiasach kwadratowych, tj .:

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

Nie mam pojęcia, jak ta składnia zostanie wywołana w Pythonie :)

Mam nadzieję że to pomoże,

Twoje zdrowie!


(EDYCJA Wt 9 kwietnia 20:57:30 2013) Cóż, myślę, że w końcu znalazłem, o co chodzi w tych nawiasach kwadratowych w linijkach ; są „listami” (najwyraźniej); najpierw zwróć uwagę na 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>

Zatem polecenie w okrągłych nawiasach / nawiasach jest postrzegane jako „obiekt generatora”; jeśli wykonamy „iterację” przez wywołanie next()- wówczas polecenie w nawiasie zostanie wykonane (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 - pamiętaj, że nie musimy dzwonić, next()aby wykonać polecenie, wykonuje się je natychmiast po przypisaniu; Jednak później inspekcja wykaże, że ajest None:

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

Nie pozostawia to wiele informacji do wyszukiwania, w przypadku nawiasów kwadratowych - ale natknąłem się na tę stronę, którą, jak sądzę, wyjaśnia:

Wskazówki i porady dotyczące języka Python - Pierwsze wydanie - Samouczki dotyczące języka Python | Dream.In.Code :

Jeśli pamiętacie, standardowy format generatora jednowierszowego jest rodzajem pętli jednowierszowej „w” w nawiasach. W ten sposób powstanie iterowalny obiekt „jeden strzał”, który jest obiektem, w którym można iterować tylko w jednym kierunku i którego nie można ponownie użyć po osiągnięciu końca.

„Zrozumienie listy” wygląda prawie tak samo jak zwykły generator jednowierszowy, z tym wyjątkiem, że zwykłe nawiasy kwadratowe - () - są zastępowane nawiasami kwadratowymi - []. Główną zaletą alistycznego rozumienia jest to, że tworzy „listę”, a nie „iteracyjny” obiekt iteracyjny, dzięki czemu można przechodzić przez niego w przód iw tył, dodawać elementy, sortować itp.

I rzeczywiście jest to lista - jest to tylko jej pierwszy element, 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

Zrozumienia list są w inny sposób udokumentowane w 5. Struktury danych: 5.1.4. Zrozumienia list - dokumentacja Python v2.7.4 jako „ Zrozumienia list zapewniają zwięzły sposób tworzenia list”; przypuszczalnie właśnie w tym przypadku obowiązuje ograniczona „wykonywalność” list w jednowierszowych liniach.

Cóż, mam nadzieję, że nie jestem tutaj zbyt daleko od znaku ...

EDYCJA 2: a tutaj jest linia poleceń z jednym wierszem z dwoma nie zagnieżdżonymi pętlami for; oba ujęte w nawiasy kwadratowe „rozumienia 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” bma teraz dwa elementy, ponieważ jej pętla for jawnie uruchomiła się dwukrotnie; jednak wynik sys.stdout.write()w obu przypadkach był (najwyraźniej) None.

sdaau
źródło
4

Ten wariant jest najbardziej przenośny do umieszczania skryptów wieloliniowych w wierszu poleceń w systemie Windows i * nix, py2 / 3, bez potoków:

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

(Żaden z innych przykładów tu przedstawionych do tej pory tego nie zrobił)

Neat w systemie 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 na bash / * nix to:

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

Ta funkcja zamienia dowolny skrypt wielowierszowy w przenośny wiersz poleceń:

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

Stosowanie:

>>> 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\"\"\"')"

Dane wejściowe były:

print 'AA   A'
try:
 for i in 1, 2, 3:
  print i / 0
except:
 print """longer
message"""
kxr
źródło
++ dla kąta międzyplatformowego i konwertera. Twoje pierwsze polecenie jest tak dobre, jak to możliwe pod względem przenośności (pomijając PowerShell), ale ostatecznie nie ma jednej, w pełni niezawodnej składni wieloplatformowej, ponieważ potrzeba użycia podwójnych cudzysłowów niesie ryzyko niepożądanego rozszerzenia powłoki, z Windows wymagający zmiany znaczenia innych znaków niż powłoki podobne do POSIX. W programie PowerShell v3 lub nowszym możesz sprawić, by wiersze poleceń działały, wstawiając opcję „stop-parsing” --%przed argumentem ciągu poleceń.
mklement0
@ mklement0 „ niechciane rozszerzenia powłoki ”: cóż, wstawianie rozszerzeń powłoki do czegoś w rodzaju print "path is %%PATH%%"resp. print "path is $PATH"jest zwykle opcją, którą chce się w skrypcie lub wierszu poleceń - chyba że unika się rzeczy, jak zwykle dla platformy. To samo z innymi językami. (Sama składnia Pythona nie sugeruje regularnie używania% i $ w konkurencyjny sposób.)
kxr
Jeśli wstawisz odwołania do zmiennych powłoki bezpośrednio do kodu źródłowego Pythona, z definicji nie będzie on przenośny. Chodzi mi o to, że nawet jeśli zamiast tego konstruujesz odwołania do platformy w oddzielnych zmiennych, które przekazujesz jako argumenty do pojedynczej komendy Pythona „bez powłoki” , to może nie zawsze działać, ponieważ nie możesz zabezpieczyć przenośnie łańcucha cudzysłowu : np. co jeśli potrzebujesz literału $foo w kodzie Pythona? Jeśli uciekniesz od niego, tak jak \$foona korzyść pocisków podobnych do POSIX, cmd.exenadal zobaczysz dodatkowe \ . To może być rzadkie, ale warto o tym wiedzieć.
mklement0
Próbuje to zrobić w programie Windows PowerShell, ale problem polega na tym, że python -c exec („” „...” ”)) nie generuje żadnych danych wyjściowych, bez względu na to, czy kod w ... można wykonać albo nie; Mógłbym tam umieścić bełkot, a wynik byłby taki sam. Wydaje mi się, że skorupa „zjada” zarówno strumienie standardowe, jak i standardowe - jak mogę je wypluć?
Yury
1

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 odwrotny dla nowej linii w instrukcji sys.stdout.write.

Devilholk
źródło
Działa to, ale ponieważ używasz echo -e, co jest niestandardowe i wymaga bash, kshlub zshrównie dobrze możesz użyć $'...'łańcucha bezpośrednio, co również upraszcza ucieczkę:python -c $'import sys\nsys.stdout.write("Hello World!\\n")'
mklement0
Ta odpowiedź działa, inne odpowiedzi nie działają dla Python3
1

Chciałem rozwiązania o następujących właściwościach:

  1. Czytelny
  2. Przeczytaj standardowe wejście do przetwarzania danych wyjściowych innych narzędzi

Oba wymagania nie zostały podane w innych odpowiedziach, więc oto jak czytać stdin podczas wykonywania wszystkiego w wierszu poleceń:

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
)
Nacięcie
źródło
0

jest jeszcze jedna opcja, sys.stdout.write zwraca None, która utrzymuje pustą listę

cat somefile.log | python -c "import sys; [linia dla linii w sys.stdin jeśli sys.stdout.write (linia * 2)]"

użytkownik993533
źródło
0

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życie stdin do odczytu danych wejściowych. Wewnętrznie powłoka tworzy plik tymczasowy dla zawartości polecenia wejściowego.

Thava
źródło
++ za „nieużywanie” standardowego skryptu z samym skryptem (chociaż -c "$(...)"robi to samo i jest zgodny z POSIX); nadać <(...)konstruktowi nazwę: podstawienie procesu ; działa również w kshi zsh.
mklement0