Przekaż tekst do programu oczekującego pliku

30

Powiązane z pytaniem, które zadałem na temat przepełnienia stosu: przekazanie wielu wierszy kodu do pliku wsadmin.sh? .

Mam jako ciąg kilka wierszy danych wejściowych, które muszę wprowadzić do polecenia. Komenda akceptuje jednak tylko plik pełen danych wejściowych.

Czy jest jakiś sposób, aby zapisać wiersze w tymczasowym pliku lub potoku, który nigdy nie jest zapisywany na dysku, a następnie podawany bezpośrednio do programu?

Jak mogę zdobyć rurę, wprowadzić do niej dane wejściowe, przekazać tę komendę do polecenia, a następnie pozbyć się rury?

ArtOfWarfare
źródło
2
Czy możesz dodać przykład polecenia, którego używasz, i jak ma zostać wywołane?
Przełom
2
Czy to oznacza, że ​​program nie akceptuje standardowego wejścia?
Léo Lam,
Zgadzam się z obu komentatorami powyżej. Niemożliwe jest sugerowanie czegokolwiek, co mogłoby działać bez znajomości specyfikacji programu.
Larssend,

Odpowiedzi:

27

Innym rozwiązaniem jest użycie procesu podstawiania w Bash. Jeśli twój system nazwał rury, możesz użyć tej funkcji.

Używa się go w następujący sposób:

program_expecting_a_file <(list)

gdzie listjest sekwencją poleceń powłoki (właściwie potoków; pełne szczegóły są tutaj ). listzostanie wykonany, a jego wyjście zostanie podłączone do potoku. Nazwa potoku jest następnie przekazywana do Twojego programu.

UWAGA: spacje nie są dozwolone między <a (.

(Inne podstawienie >(list)działa również tak, jak można się spodziewać).

W twoim konkretnym przypadku możesz użyć

program_expecting_a_file <(echo "$your_strings")

chociaż może się okazać, że rozwiązanie @ meuh jest bardziej eleganckie.

Aktualizacja: wiele przykładów użycia można znaleźć w przewodniku Advanced Bash Scripting Guide .

Edward
źródło
Pozostałe dwie nie działały nawet w najbardziej trywialnych przypadkach. Twój zdaje testy, które do tej pory na niego rzuciłem. Na razie głosowałem za tobą. Wrócę i oznaczę to jako zaakceptowane, jeśli zrobi wszystko, czego potrzebuję.
ArtOfWarfare
Twoje działa idealnie. Jeśli chcesz, możesz dodać to do powiązanego pytania na StackOverflow, a ja też mogę je zaakceptować. stackoverflow.com/questions/31374202/…
ArtOfWarfare
Cześć @ ArtOfWarfare, cieszę się, że mogłem pomóc. Jest tam już komentarz dotyczący tego samego proponowanego rozwiązania, więc nie byłoby dla mnie właściwe zamieszczanie tam odpowiedzi.
Edward
Opublikowałeś swoje rozwiązanie, zanim on to zrobił. W każdym razie poprosiłem go, aby zmienił swój komentarz na odpowiedź, abym mógł ją zaakceptować. Jeśli żadne z was nie opublikuje odpowiedzi w ciągu ~ 24 godzin na to pytanie, po prostu opublikuję odpowiedź, aby ją zaakceptować (nie lubię pozostawiać pytań bez odpowiedzi, gdy tylko znajdę odpowiedź. po prostu złe maniery dla przyszłych czytelników / potencjalnych odpowiedzi na pytanie.)
ArtOfWarfare
Cześć @ ArtOfWarfare, jestem absolutnie w porządku z tym, co proponujesz!
Edward
15

Możesz użyć bash tutaj-doc . Na przykład,

$ cat -n <<<'a
> b'
 1  a
 2  b

Jeśli masz coś w zmiennej bash, możesz ją również interpolować: np <<<"path is $PATH".


Jeśli twoje polecenie nalega na nazwę pliku, możesz go podać /dev/stdin. Na przykład:

$ sed -f /dev/stdin <<<'s/a/b/'

produkuje wyjście: s/b/b/.

meuh
źródło
Pytanie, czy polecenie przyjmuje dane wejściowe stdin, nie jest jasne , a jeśli nie, to nie zadziała. Mam nadzieję, że PO wyjaśni.
David Z
1
:( - Wydawało się to bardzo obiecujące, ale kiedy spróbowałem, dostałem komunikat o błędzie"-f" option must be followed by a file name.
ArtOfWarfare
Dokument tutaj jest dla standardowego. Jeśli twoje polecenie absolutnie potrzebuje -fnazwy pliku, podaj nazwę pliku /dev/stdin. Zobacz moją edycję.
Meuh
Myślę, że po edycji jest to absolutnie realna opcja!
Edward
1
+1 za /dev/stdinsugestię. Program, który próbuję wywołać, przyjmuje tylko nazwę pliku, więc połączyłem się /dev/stdinz heredoc.
Huw Walters
7

W zależności od tego, co jest w scenariuszu, to może być w stanie użyć specjalnego pliku - (minus), który stoi na stdin

$ mycmd -
Line 1
Line 2
^D

Inną metodą, która może Ci pomóc, jest otwarcie pliku, /dev/fd/0który znowu oznacza stdin .

Trzecią opcją może być utworzenie FIFO (First In First Out). To jest jak plik, ale ma dwa końce - piszesz na jednym końcu, a czytasz na drugim.

-- Process 1 --                  -- Process 2 --
$ mkfifo foo
$ cat foo
<waits>                          $ echo hello > foo
hello                            $
$ rm foo
Majenko
źródło
3
Warto zauważyć, że program musi być napisany, aby interpretować w -ten sposób - nie jest to cecha powłoki ani systemu operacyjnego. Oczywiście, o ile wiem, większość standardowych narzędzi Linuksa stosuje się do tej konwencji.
David Z
1
Nie. To nie działa dla programu. Istnieje tryb interaktywny, ale chcę przekazać polecenia do wykonania tego programu z innego programu i nie chcę dostać się do króliczej nory expect.
ArtOfWarfare
@ArtOfWarfare Właśnie dodałem trzecią opcję, która może działać.
Majenko,
Niezła odpowiedź! Druga i trzecia opcja są w zasadzie podobne do <()rozwiązania, ale bardziej wyraźne - co może być bardzo przydatne!
Edward
4

Istnieje inna opcja podobna do mycmd -rozwiązania, ale nawet w przypadku programów, które nie obsługują -konkretnie:

$ mycmd /dev/stdin
Line 1
Line 2
^D

/dev/stdin wydaje się być związany z systemem operacyjnym i działa dla mnie na Debian GNU / Linux, ale nie jestem pewien, gdzie jeszcze to zadziała.

Axel Beckert
źródło
1
Wygląda na to, że może działać, ale co to jest ^D?
ArtOfWarfare
^Djest powszechną notacją do naciskania Ctrl-D. ^ D ma tutaj semantykę „końca strumienia wejściowego”. Prawdopodobnie jest częściej widoczny w ^Club ^Zktóry oznacza naciśnięcie Ctrl-C odpowiednio do naciśnięcia Ctrl-Z.
Axel Beckert
1
Wydaje się, że to działa, ale jak mam programowo włożyć rzeczy, /dev/stdina następnie je zamknąć?
ArtOfWarfare
1
Wystarczy potokować coś do tego polecenia i powinno działać, tj cat content | mycmd /dev/stdin. Wyobraź sobie inne polecenia niż cattutaj.
Axel Beckert