Używam Pythona -c
do 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.
python
shell
command-line
heredoc
martineau
źródło
źródło
Odpowiedzi:
mógłbyś
lub bez rur:
lub
lub odpowiedź @ SilentGhost / odpowiedź @ Crast
źródło
python -c "exec(\"import sys\nfor r in range(10): print('rob')\")"
ten styl może być również używany w plikach makefile (i w rzeczywistości jest używany dość często).
lub
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 ).
źródło
<<EOF
. Zauważ jednak, że lepiej cytować separator - np.<<'EOF'
- aby zabezpieczyć zawartość tego dokumentu przed rozszerzeniem powłoki z góry .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ą:
Jeśli import będący instrukcją byłby problemem, działałoby to, ale nie:
W bardzo prostym przykładzie możesz przepisać go w następujący sposób:
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
.py
plik, który zamiast tego wykonuje twój makefile?źródło
- Aby ta odpowiedź działała również w Pythonie 3.x ,
print
jest wywoływana jako funkcja : w 3.x działa tylkoprint('foo')
, a 2.x również akceptujeprint 'foo'
.- Aby zapoznać się z perspektywą obejmującą wiele platform, która obejmuje system Windows , zobacz pomocną odpowiedź kxr .
W
bash
,ksh
lubzsh
:Użyj ciągu ANSI C (
$'...'
), który pozwala\n
reprezentować znaki nowej linii, które są rozwijane do rzeczywistych linii przed przekazaniem ciągu dopython
:Zwróć uwagę na instrukcje
\n
międzyimport
ifor
, 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.argv
pomocą skryptu Python: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:\
wystąpienia w oryginalnym kodzie źródłowym.\<char>
Sekwencje - jak\n
w tym przypadku, ale również zwykłe podejrzanych, takie jak\t
,\r
,\b
- spienia poprzez$'...'
(patrzman printf
dla obsługiwanych sekwencji)'
Instancje ucieczki jak\'
.Jeśli musisz pozostać zgodny z POSIX :
Użyj
printf
z podstawieniem polecenia :Aby bezpiecznie pracować z tego typu ciągiem:
\
wystąpienia w oryginalnym kodzie źródłowym.\<char>
Sekwencje - jak\n
w tym przypadku, ale również zwykłe podejrzanych, takie jak\t
,\r
,\b
- są rozszerzane przezprintf
(patrzman printf
dla obsługiwanych sekwencje).Przekaż pojedynczy ciąg znaków
printf %b
i 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ę
$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 za pomocą argumentów i dostęp do nich za pośrednictwem
sys.argv
Pythona; 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.\
przeszkadza własne przetwarzanie powłoki w łańcuchach cudzysłowów; na przykład, aby Python wygenerował dosłowny wynikro\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ć kod
stdin
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
,ksh
lubzsh
:Połącz ciąg ANSI cytowany w C (
$'...'
) z ciągiem tutaj (<<<...
):-
mówipython
jawnie 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:Jeśli musisz pozostać zgodny z POSIX :
Użyj
printf
jak wyżej, ale z potokiem , aby przekazać dane wyjściowe przez stdin:Z argumentem:
źródło
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 :Instrukcje złożone nie mogą być zawarte w tym samym wierszu z innymi instrukcjami za pomocą średników - dlatego robienie tego z
-c
flagą 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ń ,-
: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ą
<<
:Umieszczanie cudzysłowów
EOF
zapobiega 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:
Aby uniknąć rozszerzenia powłoki, użyj cudzysłowów:
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:
Krytyka zaakceptowanej odpowiedzi (i innych)
Nie jest to zbyt czytelne:
Niezbyt czytelny i dodatkowo trudny do debugowania w przypadku błędu:
Być może nieco bardziej czytelny, ale wciąż dość brzydki:
Będziesz miał zły czas, jeśli masz
"
w swoim pytonie:Nie nadużywaj
map
ani nie wymieniaj wyrażeń w celu uzyskania pętli for:Wszystkie są smutne i złe. Nie rób ich.
źródło
bash
,ksh
lubzsh
) 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).po prostu użyj return i wpisz go w następnym wierszu:
źródło
python $(srcdir)/myscript.py
dla wielkiej sprawiedliwości.$ 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.
źródło
Problem nie dotyczy
import
oświadczenia. Problem polega na tym, że instrukcje przepływu sterowania nie działają wbudowane w komendzie python. Zastąp toimport
oś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.
źródło
Jeśli twój system jest zgodny z Posix.2, powinien dostarczyć
printf
narzędzie:źródło
printf %b '...' | python
celu zwiększenia niezawodności, ponieważ zapobiegaprintf
interpretacji 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.single/double quotes
ibackslash
wszędzie:Dużo lepiej:
źródło
(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.write
zamiastprint
( różnica polega na tym, żesys.stdout.write
przyjmuje argumenty jako funkcję, w nawiasach - podczasprint
gdy nie ), to w przypadku jednowierszowego można uniknąć odwrócenia kolejności polecenia ifor
usunięcia średnika, i zawarcie polecenia w nawiasach kwadratowych, tj .: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:
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):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, żea
jestNone
: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 :
I rzeczywiście jest to lista - jest to tylko jej pierwszy element, gdy tylko zostanie wykonany:
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”:
Zauważ, że druga „lista”
b
ma teraz dwa elementy, ponieważ jej pętla for jawnie uruchomiła się dwukrotnie; jednak wyniksys.stdout.write()
w obu przypadkach był (najwyraźniej)None
.źródło
Ten wariant jest najbardziej przenośny do umieszczania skryptów wieloliniowych w wierszu poleceń w systemie Windows i * nix, py2 / 3, bez potoków:
(Żaden z innych przykładów tu przedstawionych do tej pory tego nie zrobił)
Neat w systemie Windows to:
Neat na bash / * nix to:
Ta funkcja zamienia dowolny skrypt wielowierszowy w przenośny wiersz poleceń:
Stosowanie:
Dane wejściowe były:
źródło
--%
przed argumentem ciągu poleceń.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.)$foo
w kodzie Pythona? Jeśli uciekniesz od niego, tak jak\$foo
na korzyść pocisków podobnych do POSIX,cmd.exe
nadal zobaczysz dodatkowe\
. To może być rzadkie, ale warto o tym wiedzieć.Ten skrypt zapewnia interfejs wiersza polecenia podobny do Perla:
Pyliner - Skrypt uruchamiający dowolny kod Pythona w wierszu poleceń (przepis na Python)
źródło
Kiedy musiałem to zrobić, używam
Zwróć uwagę na potrójny ukośnik odwrotny dla nowej linii w instrukcji sys.stdout.write.
źródło
echo -e
, co jest niestandardowe i wymagabash
,ksh
lubzsh
ró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")'
Chciałem rozwiązania o następujących właściwościach:
Oba wymagania nie zostały podane w innych odpowiedziach, więc oto jak czytać stdin podczas wykonywania wszystkiego w wierszu poleceń:
źródło
jest jeszcze jedna opcja, sys.stdout.write zwraca None, która utrzymuje pustą listę
źródło
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:
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.
źródło
-c "$(...)"
robi to samo i jest zgodny z POSIX); nadać<(...)
konstruktowi nazwę: podstawienie procesu ; działa również wksh
izsh
.