Как получить ввод диалогового окна, направленный на переменную?

Я учил себя написанию сценариев bash и столкнулся с проблемой. Я написал скрипт для получения ввода от пользователя с помощью команды read и превращения этого ввода в переменную для последующего использования в скрипте. Сценарий работает, но ....

Я хотел бы иметь возможность настроить его с помощью «диалога». Я обнаружил, что

'dialog --inputbox' будет направлять вывод в 'stderr', и чтобы получить этот ввод как переменную, вы должны направить его в файл и затем извлечь его. Код, который я нашел, чтобы объяснить это:

#!/bin/bash
dialog --inputbox \

"What is your username?" 0 0 2> /tmp/inputbox.tmp.$

retval=$?

input=`cat /tmp/inputbox.tmp.$`

rm -f /tmp/inputbox.tmp.$

case $retval in
0)

echo "Your username is '$input'";;
1)

echo "Cancel pressed.";;

esac

Я вижу, что он отправляет sdterr в /tmp/inputbox.tmp.$$ с 2>, но выходной файл выглядит как «inputbox. tmp.21661. Когда я пытаюсь просмотреть файл, появляется сообщение об ошибке. Поэтому я все еще не могу получить пользовательский ввод из --inputbox как переменную.

Пример сценария:

echo "  What app would you like to remove? "

read dead_app

sudo apt-get remove --purge $dead_app

Итак, как вы можете видеть, это базовый сценарий. Можно ли вообще получить переменную как слово из dialog --inputbox?

18
задан 4 July 2014 в 11:58

6 ответов

: D я не могу объяснить его!!! Если можно понять то, что они говорят в ссылке: Усовершенствованное Руководство по созданию сценариев Bash: Глава 20. Перенаправление ввода-вывода , запишите новый ответ, и я дам Вам 50rep , щедрость

была дана, поскольку объяснение видит ответ ByteCommander .:) Это - часть истории.

exec 3>&1;
result=$(dialog --inputbox test 0 0 2>&1 1>&3);
exitcode=$?;
exec 3>&-;
echo $result $exitcode;

Источник: Диалоговое окно в ударе не захватывает переменные правильно
Ссылка: Усовершенствованное Руководство по созданию сценариев Bash: Глава 20. Перенаправление ввода-вывода

7
ответ дан 4 July 2014 в 11:58

Это работает на меня:

#!/bin/bash
input=$(dialog --stdout --inputbox "What is your username?" 0 0)
retval=$?

case $retval in
${DIALOG_OK-0}) echo "Your username is '$input'.";;
${DIALOG_CANCEL-1}) echo "Cancel pressed.";;
${DIALOG_ESC-255}) echo "Esc pressed.";;
${DIALOG_ERROR-255}) echo "Dialog error";;
*) echo "Unknown error $retval"
esac

страница руководства dialog говорит о - stdout:

Прямой вывод к стандартному выводу. Эта возможность предоставляется для совместимости с Xdialog, однако использование его в портативных сценариях не рекомендуется, начиная с проклятий обычно пишет его экранные обновления стандартного вывода. При использовании этой опции диалоговое окно пытается вновь открыть терминал, таким образом, это может записать в дисплей. В зависимости от платформы и Вашей среды, которая может перестать работать.

кто-либо может сказать, в которой платформе или среде это не работает? Перенаправление dialog производит к 2>&1 >/dev/tty вместо этого работа лучше затем?

4
ответ дан 4 July 2014 в 11:58

Ответ, предоставленный Sneetsher, несколько более изящен, но я могу объяснить что случилось: значение $ отличается в обратных галочках (потому что оно запускает новую оболочку, и $ PID текущей оболочки). Вы захотите поместить имя файла в переменную, затем относиться к той переменной повсюду вместо этого.

#!/bin/bash
t=$(mktemp -t inputbox.XXXXXXXXX) || exit
trap 'rm -f "$t"' EXIT         # remove temp file when done
trap 'exit 127' HUP STOP TERM  # remove if interrupted, too
dialog --inputbox \
    "What is your username?" 0 0 2>"$t"
retval=$?
input=$(cat "$t")  # Prefer $(...) over `...`
case $retval in
  0)    echo "Your username is '$input'";;
  1)    echo "Cancel pressed.";;
esac

В этом случае, избегая временного файла было бы лучшее решение, но будет много ситуаций, где Вы не можете избежать временного файла.

3
ответ дан 4 July 2014 в 11:58

В случае, если кто-то еще также приземлился здесь от Google, и хотя этот вопрос спрашивает специально для удара, вот другая альтернатива:

можно использовать zenity. Zenity графический утилита, которая может быть используемые внутренние сценарии удара. Но конечно это потребовало бы X-сервера как user877329 законно указанный.

sudo apt-get install zenity

Тогда в Вашем сценарии:

RETVAL=`zenity --entry --title="Hi" --text="What is your username"`

Полезная ссылка .

4
ответ дан 4 July 2014 в 11:58

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

При чтении страницы справочника для диалогового окна существует опция --output-fd, который позволяет Вам явно устанавливать, куда вывод идет (STDOUT 1, STDERR 2), вместо значением по умолчанию, идущим в STDERR.

Рев Вы видите, что я выполняю образец dialog команда, с явным утверждением, которые производят, должна перейти к дескриптору файла 1, который позволяет мне сохранять его в MYVAR.

MYVAR=$(dialog --inputbox "THIS OUTPUT GOES TO FD 1" 25 25 --output-fd 1)

enter image description here

Используя именованные каналы

Альтернативный подход, который имеет большой скрытый потенциал, должен использовать что-то известное как именованный канал.

#!/bin/bash

mkfifo /tmp/namedPipe1 # this creates named pipe, aka fifo

# to make sure the shell doesn't hang, we run redirection 
# in background, because fifo waits for output to come out    
dialog --inputbox "This is an input box  with named pipe" 40 40 2> /tmp/namedPipe1 & 

# release contents of pipe
OUTPUT="$( cat /tmp/namedPipe1  )" 


echo  "This is the output " $OUTPUT
# clean up
rm /tmp/namedPipe1 

enter image description here

Более всесторонний обзор ответа user.dz с альтернативным подходом

Исходный ответ user.dz и объяснением ByteCommander тот и предоставляет хорошее решение и обзор того, что это делает. Однако я полагаю, что более глубокий анализ мог быть выгодным для объяснения, почему он работает.

В первую очередь, важно понять две вещи: что является проблемой, мы пытаемся решить и что является базовыми работами механизмов оболочки, с которыми мы имеем дело. Задача состоит в том, чтобы получить вывод команды через замену команды. В соответствии с упрощенным обзором, который все знают, замены команды получают stdout из команды и позволяют ему быть снова использованным чем-то еще. В этом случае, result=$(...) часть должна сохранить вывод любой команды, определяется ... в названную переменную result.

Под капотом замена команды на самом деле реализована как канал, где существует дочерний процесс (фактическая команда, которая работает), и процесс считывания (который сохраняет вывод к переменной). Это очевидно с простой трассировкой системных вызовов. Заметьте, что дескриптор файла 3 является концом чтения канала, в то время как 4 конец записи. Для дочернего процесса echo, который пишет в stdout - дескриптор файла 1, тот дескриптор файла является на самом деле копией дескриптора файла 4, который является концом записи канала. Заметьте это stderr не играет роль здесь, просто потому что это - соединение канала stdout только.

$ strace -f -e pipe,dup2,write,read bash -c 'v=$(echo "X")'
...
pipe([3, 4])                            = 0
strace: Process 6200 attached
[pid  6199] read(3,  <unfinished ...>
[pid  6200] dup2(4, 1)                  = 1
[pid  6200] write(1, "X\n", 2 <unfinished ...>
[pid  6199] <... read resumed> "X\n", 128) = 2
[pid  6200] <... write resumed> )       = 2
[pid  6199] read(3, "", 128)            = 0
[pid  6200] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=6200, si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
+++ exited with 0 +++

Давайте вернемся к исходному ответу в течение секунды. Так как теперь мы знаем это dialog пишет поле TUI в stdout, ответ на stderr, и в замене команды stdout передается по каналу где-то в другом месте, у нас уже есть часть решения - мы должны повторно соединить дескрипторы файлов проводом таким способом который stderr будет передан по каналу к процессу читателя. Это 2>&1 часть ответа. Однако, что мы делаем с полем TUI?

Это - то, где дескриптор файла 3 входит. dup2() syscall позволяет нам дескрипторам дубликата файла, заставляя их эффективно обратиться к тому же месту, все же мы можем управлять ими отдельно. Дескрипторы файлов процессов, которые имеют терминал управления, присоединенный на самом деле, указывают на определенное оконечное устройство. Это очевидно, если Вы делаете

$ ls -l /proc/self/fd
total 0
lrwx------ 1 user1 user1 64 Aug 20 10:30 0 -> /dev/pts/5
lrwx------ 1 user1 user1 64 Aug 20 10:30 1 -> /dev/pts/5
lrwx------ 1 user1 user1 64 Aug 20 10:30 2 -> /dev/pts/5
lr-x------ 1 user1 user1 64 Aug 20 10:30 3 -> /proc/6424/fd

где /dev/pts/5 мое текущее устройство псевдотерминала. Таким образом, если мы можем так или иначе сохранить это место назначения, мы можем все еще записать поле TUI на терминальный экран. Это что exec 3>&1 делает. Когда Вы называете команду с перенаправлением command > /dev/null например, оболочка передает, это - stdout дескриптор файла и затем использует dup2() записать тот дескриптор файла в /dev/null. exec команда выполняет что-то подобное dup2() дескрипторы файлов для целой сессии оболочки, таким образом заставляя любую команду уже наследовать перенаправленный дескриптор файла. То же с exec 3>&1. Дескриптор файла 3 будет теперь относиться к к терминалу управления, и любая команда, которая работает на той сессии оболочки, будет знать об этом.

Итак, когда result=$(dialog --inputbox test 0 0 2>&1 1>&3); происходит, оболочка создает канал для диалогового окна для записи, но также и 2>&1 сначала сделает дескриптор файла команды, который будет дублирован на дескриптор файла записи того канала (таким образом заставляющий вывод пойти для чтения конца канала и в переменную), в то время как дескриптор файла 1 будет дублирован на 3. Это сделает дескриптор файла 1, все еще относятся к терминалу управления, и диалоговое окно TUI обнаружится на экране.

Теперь, существует на самом деле сокращение от текущего терминала управления процесса, который является /dev/tty. Таким образом решение может быть упрощено без использования дескрипторов файлов, просто в:

result=$(dialog --inputbox test 0 0 2>&1 1>/dev/tty);
echo "$result"

Ключевые вещи помнить:

  • дескрипторы файлов наследованы от оболочки каждой командой
  • замена команды реализована как канал
  • дублированные дескрипторы файлов назовут то же место исходным, но мы можем управлять каждым дескриптором файла отдельно

См. также

14
ответ дан 4 July 2014 в 11:58

:D Я не могу объяснить это!!! Если можно понять то, что они говорят в Усовершенствованном Руководстве по созданию сценариев Bash: Глава 20. Перенаправление ввода-вывода, запишите новый ответ, и я дам Вам 50rep:

exec 3>&1;
result=$(dialog --inputbox test 0 0 2>&1 1>&3);
exitcode=$?;
exec 3>&-;
echo $result $exitcode;

Ссылка: Диалоговое окно в ударе не захватывает переменные правильно

^ ответ от @Sneetsher (4 июля 2014)

Согласно просьбе я попытаюсь объяснить, что этот отрывок делает линию за линией.

Обратите внимание, что я упрощу его путем исключения весь ; точки с запятой в концах строки, потому что они не необходимы, если мы пишем одну команду на строку.

Ввод-вывод - Потоки:

Во-первых, необходимо понять коммуникационные потоки. Существует 10 потоков, пронумерованных от 0 до 9:

  • Поток 0 ("STDIN"):
    "Стандартный вход", входной поток по умолчанию для чтения данных с клавиатуры.

  • Поток 1 ("STDOUT"):
    "Стандартный вывод", поток вывода по умолчанию раньше показывал обычный текст в терминале.

  • Поток 2 ("STDERR"): "Стандартная погрешность", поток вывода по умолчанию раньше отображал ошибки или другой текст для особых целей в терминале.

  • Потоки 3-9:
    Дополнительные, свободно применимые потоки. Они не используются по умолчанию и не существуют, пока что-то не пытается использовать их.

Обратите внимание, что все "потоки" внутренне представлены дескрипторами файлов в /dev/fd (который является символьной ссылкой на /proc/self/fd который содержит другую символьную ссылку для каждого потока... это немного сложно и не важное для их поведения, таким образом, я останавливаюсь здесь.). Стандартные потоки также имеют /dev/stdin, /dev/stdout и /dev/stderr (которые являются символьными ссылками снова, и т.д....).

Сценарий:

  • exec 3>&1
    

    Встроенный Bash exec может использоваться для применения потокового перенаправления к оболочке, которая означает, что влияет на весь после команд. Для большего количества информации, выполненной help exec в Вашем терминале.

    В этом особом случае поток 3 перенаправляется для потоковой передачи 1 (STDOUT), который означает все, что мы отправляем в поток 3, позже появится в нашем терминале, как будто он обычно печатался к STDOUT.

  • result=$(dialog --inputbox test 0 0 2>&1 1>&3)
    

    Эта строка состоит из многих частей и синтаксических структур:

    • result=$(...)
      Эта структура выполняет команду в скобках и присваивает вывод (STDOUT) переменной удара result. Это читаемо через $result. Все это описано так или иначе в veeeery looong man bash.

    • dialog --inputbox TEXT HEIGHT WIDTH
      Эта команда показывает поле TUI с данным ТЕКСТОМ, полем ввода текста и двумя кнопками OK и CANCEL. Если хорошо будет выбран, выходы команды с состоянием 0 и распечатает введенный текст к STDERR, если ОТМЕНА будет выбрана, то это выйдет с кодом 1 и ничего не распечатает. Для большего количества информации читать man dialog.

    • 2>&1 1>&3
      Это две команды перенаправления. Они будут интерпретироваться справа налево:

      1>&3 перенаправляет поток команды 1 (STDOUT) к пользовательскому потоку 3.

      2>&1 перенаправления впоследствии поток команды 2 (STDERR) для потоковой передачи 1 (STDOUT).

      Это означает, что все, печать команды к STDOUT теперь появляется в потоке 3, в то время как все, что было предназначено для разоблачения на STDERR теперь, перенаправляется к STDOUT.

    Таким образом, вся строка отображает текстовую подсказку (на STDOUT, который был перенаправлен для потоковой передачи 3, который оболочка снова перенаправляет назад к STDOUT в конце - посмотрите exec 3>&1 команда), и присваивается, вводимые данные (возвратился через STDERR, затем перенаправленный к STDOUT) к переменной Bash result.

  • exitcode=$?
    

    Этот код получает код выхода ранее выполняемой команды (здесь от dialog) через зарезервированную переменную Bash $? (всегда содержит последний код выхода), и просто хранит его в нашей собственной переменной Bash exitcode. Это может быть прочитано $exitcode снова. Можно искать больше информации об этом в man bash, но это могло бы требовать времени...

  • exec 3>&-
    

    Встроенный Bash exec может использоваться для применения потокового перенаправления к оболочке, которая означает, что влияет на весь после команд. Для большего количества информации, выполненной help exec в Вашем терминале.

    В этом особом случае поток 3 перенаправляется к "потоку -", который просто означает, что должен быть закрыт. Данные, отправленные в поток 3, не будут перенаправлены нигде больше с этого времени.

  • echo $result $exitcode
    

    Это простое echo команда (больше информации о man echo) просто печатает содержание двух переменных Bash result и exitcode к STDOUT. Поскольку у нас нет явных или неявных потоковых перенаправлений здесь больше, они действительно появятся на STDOUT и поэтому просто отображаться в терминале. Какое чудо!;-)

Сводка:

Во-первых, мы настраиваем оболочку для перенаправления всего, что мы отправляем в пользовательский поток 3 назад к STDOUT, так, чтобы это обнаружилось в нашем терминале.

Затем мы работаем dialog команда, перенаправьте ее исходный STDOUT к нашему пользовательскому потоку 3, потому что это должно быть отображено в конце, но мы временно должны использовать поток STDOUT для чего-то еще.
Мы перенаправляем исходный STDERR команды, куда ввод данных пользователем диалогового окна возвращается к STDOUT впоследствии.
Теперь мы можем получить STDOUT (который содержит перенаправленные данные из STDERR), и сохраните его в нашей переменной $result. Это содержит требуемый ввод данных пользователем теперь!

Мы также хотим dialog код выхода команды, который показывает нам или хорошо или ОТМЕНА, был нажат. Это значение представлено в зарезервированной переменной Bash $? и мы просто копируем его в нашу собственную переменную $exitcode.

После этого мы закрываем поток 3 снова, поскольку нам больше не нужен он, для остановки дальнейших перенаправлений его.

Наконец, мы обычно производим содержание обеих переменных $result (ввод данных пользователем диалогового окна) и $exitcode (0 для OK, 1 для ОТМЕНЫ) к терминалу.

16
ответ дан 4 July 2014 в 11:58

Другие вопросы по тегам:

Похожие вопросы: