Automatyzacja wprowadzania tekstu ze skryptu bash bez użycia EOF

10

Korzystam z systemu Ubuntu Linux. Załóżmy, że istnieje program o nazwie myprogram. Ten program monituje użytkownika o wprowadzenie danych; w szczególności użytkownik musi wpisać liczbę całkowitą po wyświetleniu monitu i nacisnąć Enter. Chciałbym zautomatyzować ten proces za pomocą skryptu bash. W szczególności chciałbym wykonać myprogram, powiedzmy, 100 razy (przy użyciu licznika, iktóry przechodzi od 1do 100). Przy każdym wykonaniu myprogramchciałbym wprowadzić bieżącą wartość ipo wyświetleniu monitu.

(Nawiasem mówiąc, myprogrambierze opcje / przełączniki -options, z których wszystkie będą stałe, a zatem określone w skrypcie bash.)

Niekompletny szkielet tego skryptu bash może być:

#!/bin/bash
for i in {1..100}
do
   myprogram -options
done

Teraz chciałbym zmodyfikować powyższy kod, aby bieżąca wartość izostała wprowadzona po wyświetleniu monitu przez program. Jak najlepiej to zrobić?

Witryna oprogramowania, którego używam, sugeruje użycie <<EOFna końcu myprogram -optionswiersza. Myślę, że to każe bashowi spojrzeć na „koniec pliku”, aby użyć danych wejściowych. Ale co jeśli nie chcę umieszczać danych wejściowych na końcu pliku? Co jeśli chciałbym umieścić go natychmiast po <<lub <?

Powodem jest to, że sprawy się skomplikują. Na przykład mogę wprowadzić licznik liczb całkowitych, jktóry zmienia się w nieliniowy, niesekwencyjny sposób. Chciałbym następnie podać bieżącą wartość jdo myprogramna każdej iteracji, ale wartość jmoże się zmieniać między wywołaniem myprogram -optionsa końcem pliku EOF.

Masz jakieś sugestie?

Andrzej
źródło
Sprawdź tego bloga - Uruchamianie programów interaktywnych
Suresh

Odpowiedzi:

14

Dla prawie wszystkich programach, zarówno echo $i | myprogram -optionsi myprogram -options <<<$ipowinno działać, przez karmienie program $ipoprzez standardowe wejście.

<fooużyje zawartości pliku o nazwie foostdin.

<<fooużyje tekstu pomiędzy tym a wierszem składającym się wyłącznie ze foostandardowego wprowadzania. To jest dokument tutaj (heredoc), jak powiedział Gilles; EOFtak naprawdę nie oznacza końca pliku, to po prostu wspólny heredok (w tym przykładzie używamy „foo”).

<<<fooużyje ciągu „foo” jako standardowego wejścia. Możesz także określić zmienną $foo, a powłoka użyje jej zawartości jako standard, jak pokazałem powyżej. Nazywa się to ciągiem znaków , ponieważ używa krótkiego łańcucha w przeciwieństwie do całego bloku, jak w heredoc. Herestrings działają w trybie bash, ale nie w /bin/sh.

Kevin
źródło
9

Składnia zalecana przez tę stronę nazywa się tutaj dokumentem . Dane wejściowe do programu plików zaczynają się bezpośrednio poniżej wiersza zawierającego <<EOFi nie kończą się na końcu skryptu, ale wierszem zawierającym dokładnie tekst EOF(uważaj, aby nie mieć dodatkowych białych znaków). Nawiasem mówiąc, możesz użyć dowolnego znacznika końcowego, który nie zawiera żadnego znaku specjalnego powłoki: EOFnie jest słowem kluczowym, jest jedynie tradycyjny.

#!/bin/bash
for i in {1..100}
do
   myprogram -options <<EOF
$i
EOF
   for j in {1..42}; do
     myprogram2 <<EOF
$i
$j
EOF
   done
done
Gilles „SO- przestań być zły”
źródło
innymi słowy, EOF w tym kontekście oznacza znacznik końca pliku , a nie rzeczywisty koniec pliku skryptu. tekst „EOF” to dowolny dowolny tekst - cokolwiek użyjesz natychmiast po znakach <<, wskaże koniec dokumentu tutaj. Zazwyczaj używam EOF, ponieważ wyróżnia się i jest bardzo mało prawdopodobne, aby znajdował się w niniejszym dokumencie, jeśli np. Programowo generuję skrypt powłoki (co robię dość często).
cas
ten pogrubiony EOF powinien być <underscore><underscore>EOF<underscore> <underscore>
cas
Korzystając z takich dokumentów tutaj, często zmieniałem znacznik końcowy na coś o wiele bardziej znaczącego (i mniej prawdopodobne, że zostanie on „losowo” dopasowany) END_OF_WHATEVER_FUNCTION. Czasami próba „zaoszczędzenia” miejsca / rozmiaru jest w rzeczywistości stratą wysiłku, ponieważ powoduje niejasności co do tego, co się faktycznie dzieje.
killermist
Jak sleepmiędzy komendami czytać ze skryptu?
boltup_im_coding
@ nieoczekiwany62 Nie rozumiem o co pytasz. Prawdopodobnie powinieneś zadać nowe pytanie na tej stronie. Pamiętaj o podaniu wystarczającego kontekstu.
Gilles 'SO - przestań być zły'
3

tutaj dokumenty, o których wspomnieli Kevin i Gilles powyżej, lub proste orurowanie będzie działać w wielu przypadkach.

W bardziej skomplikowanych sytuacjach możesz zajrzeć do Expect lub podobnego (np. Expect :: Simple CPAN moduł jest bardzo łatwą w użyciu implementacją perla). osobiście wolę moduł perla (spodziewam się, że to tcl), ale istnieją implementacje dla wielu popularnych języków skryptowych. Możliwe jest nawet napisanie bardzo prymitywnej implementacji pomysłu w sh lub bash przy użyciu while i read.

Ogólną ideą Expect i podobnych narzędzi jest oczekiwanie na określony ciąg znaków lub wzorzec na wyjściu programu, a następnie podawanie go bez względu na to, co chcesz.

Częstym przykładem jest automatyzacja logowania poprzez „oczekiwanie” (tj. Oczekiwanie) ciągu „ogin:”, wysłanie nazwy logowania, a następnie oczekiwanie ciągu „słowo:” i wysłanie hasła.

Ostatnią opcją, jeśli masz źródło mojego programu, jest po prostu zmodyfikować go, aby przyjąć dane wejściowe, które chcesz podać jako opcję wiersza poleceń. Może to być nieco więcej pracy z góry, ale będzie o wiele mniej irytujące niż bałagan z Oczekiwaniem lub przesyłanie danych do programu, który nie został zaprojektowany w taki sposób.

... i nie zapomnij przesłać łatki do myprogramu z powrotem w górę :) Nawet jeśli nie podoba ci się sposób, w jaki ją kodowałeś, może spodobać im się pomysł na dodanie tej funkcji. Deweloperzy z wyższego szczebla doceniają ludzi, którzy zrywają tyłki i wnoszą swój wkład, zamiast żądać lub narzekać.

cas
źródło