Передать текст в программу, ожидающую файл

29

Связанный с вопросом, который я задал относительно переполнения стека: передача нескольких строк кода в wsadmin.sh? ,

В качестве строки у меня есть несколько строк ввода, которые мне нужно ввести в команду. Команда, однако, принимает только файл, полный ввода.

Есть ли какой-нибудь способ, которым я мог бы сохранить строки во временном файле или канале, который никогда не будет записан на диск, а затем передать их непосредственно в программу?

Как мне получить трубку, подать входные данные в нее, передать эту трубку команде, а затем избавиться от канала?

ArtOfWarfare
источник
2
Можете ли вы добавить пример команды, которую вы используете, и как она должна вызываться?
Прорыв
2
Означает ли это, что программа не принимает стандартный ввод?
Лео Лам
Я согласен с обоими комментаторами выше. Невозможно предложить что-либо, что может работать, не зная спецификаций программы.
Ларсенд

Ответы:

25

Другое решение заключается в использовании процесса замены в Bash. Если ваша система имеет именованные каналы, вы можете использовать эту функцию.

Используется так:

program_expecting_a_file <(list)

где list- последовательность команд оболочки (на самом деле конвейеры; полная информация здесь ). listбудет выполнен, и его выход будет подключен к трубе. Имя канала затем передается в вашу программу.

ПРИМЕЧАНИЕ: пробелы не допускаются между <и (.

(Другая замена >(list)также работает, как и следовало ожидать.)

В вашем конкретном случае вы могли бы использовать

program_expecting_a_file <(echo "$your_strings")

хотя вы можете найти решение @ meuh более элегантным.

Обновление: очень много примеров использования можно найти в Расширенном руководстве по написанию сценариев Bash .

Эдвард
источник
Два других не работали даже в самых тривиальных случаях. Ваш проходит испытания, которые я бросил в этом до сих пор. Я проголосовал за ваш сейчас. Я вернусь и отмечу это как принятое, если он сделает все, что мне нужно.
ArtOfWarfare
Твой работает отлично. Если хотите, вы можете добавить его к связанному вопросу в StackOverflow, и я могу принять его там же. stackoverflow.com/questions/31374202/…
ArtOfWarfare
Привет @ArtOfWarfare, рад помочь. Там уже есть комментарий с тем же предложенным решением, поэтому было бы неправильно публиковать там ответ.
Эдвард
Вы отправили свое решение раньше, чем он. В любом случае, я попросил его изменить свой комментарий на ответ, чтобы я мог принять его. Если ни один из вас не отправит ответы в течение ~ 24 часов на этот вопрос, я просто отправлю ответ сам, чтобы я мог принять его (мне не нравится оставлять мои вопросы как оставшиеся без ответа, как только я нашел, что это за ответ. просто плохие манеры для будущих читателей / потенциальных ответчиков на вопрос.)
ArtOfWarfare
Привет @ArtOfWarfare, я абсолютно в порядке с тем, что вы предлагаете!
Эдвард
14

Вы можете использовать bash здесь-док . Например,

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

Если у вас есть что-то в переменной bash, вы также можете интерполировать это: например <<<"path is $PATH".


Если ваша команда настаивает на имени файла, вы можете указать его /dev/stdin. Например:

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

производит вывод: s/b/b/.

meuh
источник
Из вопроса не ясно, принимает ли команда ввод stdin, и если нет, это не сработает. Я надеюсь, что ОП уточняет.
Дэвид З,
1
:( - Это выглядело очень многообещающе, но когда я попробовал это, я получил сообщение об ошибке"-f" option must be followed by a file name.
ArtOfWarfare
А вот документ для стандартного ввода. Если вашей команде абсолютно необходимо -fи имя файла, укажите имя файла /dev/stdin. Смотрите мое редактирование.
Мое
Я думаю, что после внесения изменений это абсолютно приемлемый вариант!
Эдвард
+1 за /dev/stdinпредложение. Программа, которую я пытаюсь вызвать, принимает только имя файла, поэтому я объединился /dev/stdinс heredoc.
Ху Уолтерс
7

В зависимости от того, что в сценарии, вы можете использовать специальное имя файла - (минус), что означает стандартный ввод

$ mycmd -
Line 1
Line 2
^D

Другой способ, который может вам помочь, - это открыть файл, /dev/fd/0который снова обозначает stdin .

Третий вариант может заключаться в создании FIFO (First In First Out). Это похоже на файл, но у него два конца - вы пишете с одного конца и читаете с другого.

-- Process 1 --                  -- Process 2 --
$ mkfifo foo
$ cat foo
<waits>                          $ echo hello > foo
hello                            $
$ rm foo
Majenko
источник
3
Возможно, стоит отметить, что программа должна быть написана так, чтобы интерпретировать -это - это не особенность оболочки или операционной системы. Хотя, конечно, большинство стандартных утилит Linux следуют этому соглашению, насколько я знаю.
Дэвид Z
1
Нету. Это не работает для программы. Есть интерактивный режим, но я хочу передать команды для выполнения этой программе из другой программы, и я не хочу попадать в кроличью нору expect.
ArtOfWarfare
@ArtOfWarfare Я только что добавил третий вариант, который может работать.
Маженко
Хороший ответ! Второй и третий варианты в основном похожи на <()решение, но более явные - что может быть очень полезно!
Эдвард
3

Есть еще один вариант, похожий на mycmd -решение, но даже для программ, которые специально не обрабатывают -:

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

/dev/stdin Кажется, что это связано с ОС, и это работает для меня в Debian GNU / Linux, но я не уверен, где еще это будет работать.

Аксель Бекерт
источник
1
Кажется, это может сработать, но что это ^D?
ArtOfWarfare
^Dявляется общим обозначением для нажатия Ctrl-D. ^ D имеет семантику «конец входного потока» здесь. Скорее всего, это чаще всего встречается ^Cили ^Zобозначает нажатие Ctrl-C, соответственно нажатие Ctrl-Z.
Аксель Беккерт
1
Кажется, это работает, но как бы я программно поместил материал, /dev/stdinа затем закрыл его?
ArtOfWarfare
1
Просто труба - то в этой команде , и он должен работать, то есть cat content | mycmd /dev/stdin. Просто представьте разные команды, чем catздесь.
Аксель Беккерт,