Как 'читать' и отозваться эхом независимо от того, что пользователь ввел?

Я делаю этот сценарий: когда Вы вводите

"my name is [your name]"

это говорит Вам

"hi, [your name]".

Однако я не знаю, как сделать [your name] что-либо Вы вводите. Я сделал сценарий с конкретным именем, но я хочу, чтобы это отозвалось эхом безотносительно имени, которое вводит пользователь:

#!/bin/bash
read -p "Say something: " sth
  if [[ $sth = "my name is ralph" ]]
      then
          echo "Hi $(echo $sth | cut -f 4 -d ' ')"
  else
      echo "I didn't understand that"
  fi

Таким образом, это отзовется эхом Hi ralph, но как заставить его отозваться эхом Hi [your name] с любым именем Вы ввели?

1
задан 19 March 2017 в 07:39

6 ответов

Специфические особенности не даны Вами, но обычно Вы получаете имя как это.

#!/bin/bash   

regex='[Mm]y(\ name\ is\ )(\w*)'

read -p "Say something: " response

echo $response

if [[ "$response" =~ $regex ]]; then

        name=$(echo $response | cut -d' ' -f4)

        echo "Hi $name"
else
        echo "I didn't understand that"

fi
3
ответ дан 3 December 2019 в 06:21

Вы могли использовать тест regex =~ для получения то независимо от того, что прибывает после my name is:

$ read -rp "Say something: "; if [[ "$REPLY" =~ [Mm]y\ name\ is\ .* ]]; then echo "Hi "${REPLY:11}"" ; fi
Say something: my name is zanna
Hi zanna

Здесь я использовал расширение параметра , чтобы удалить первые 11 символов (my name is) и распечатать то независимо от того, что прибыло после него, но если бы пользователь ввел больше, чем их имя, то результат мог бы быть не то, что Вы хотите:

Say something: my name is pixie and I eat flowers
Hi pixie and I eat flowers

ответ George соглашения с этим использованием cut для печати только 4-го поля (но я предполагаю, пользователь мог бы ввести My name is Super Rainbow Unicorn, и Вы не могли бы хотеть, чтобы оболочка ответила только Hi Super).

больше четко и с else:

read -rp "Say something: "
if [[ "$REPLY" =~ [Mm]y\ name\ is\ .* ]]
  then 
    echo "Hi "${REPLY:11}""
  else
    echo "I didn't understand that."
fi
3
ответ дан 3 December 2019 в 06:21

У Вас есть проблема с Вашим сценарием, потому что Вы используете = оператор, который делает присвоение на Ваш $sth переменная вместо того, чтобы делать сравнение между двумя.

Использование двойной равный символ (==) вместо сингла (=). Эти == оператор для соответствия шаблона.

Изменение Ваш условный оператор:

Изменение от:

if [[ $sth = "my name is ralph" ]]

Изменение в:

if [[ $sth == "my name is ralph" ]]
-1
ответ дан 3 December 2019 в 06:21

Zanna и George оба сделали правильную вещь в использовании regexes, но затем не дошли на самом деле использовать поддержку regex Bash для извлечения имени. С чем-то как:

regex='[Mm]y(\ name\ is\ )(\w*)'
read -p "Say something: " response

if [[ "$response" =~ $regex ]]; then

После [[ ]] тест regex сделан, удар делает доступным regex группы подобранный в BASH_REMATCH массив. Например (с входом My name is foo bar baz):

$ printf "%s\n" "${BASH_REMATCH[@]}"
My name is foo
 name is 
foo

Так, изменяя группы немного:

$ regex='My name is (\w.*)'
$ [[ "$response" =~ $regex ]]
$ printf "%s\n" "${BASH_REMATCH[@]}"
My name is foo bar baz
foo bar baz

Лучше все еще можно сказать удару использовать нечувствительное к регистру соответствие regex:

shopt -s nocasematch

Объединение всего этого:

regex='My name is (\w.*)'
read -rp "Say something: "
shopt -s nocasematch
if [[ $REPLY =~ $regex ]]
then 
    echo "Hi ${BASH_REMATCH[1]}"
else
    echo "I didn't understand that."
fi

(Кроме того, это предоставляет себя довольно легко извлечению первого слова имени или последнего.)

2
ответ дан 3 December 2019 в 06:21

Две строки кода: printf для подсказки, sed для всего остального.

Вы могли бы рассмотреть не использование read вообще. Существует много стандартных утилит, которые могут использоваться собой или в сценариях. Одна утилита, которая работает на это, sed, потоковый редактор.

printf 'Say something: '
sed -r 's/^[Mm]y name is (.+)/hi, \1/; tQ; s/.*/I didn\x27t understand that/; :Q; q'

Именно. Это - все, в чем Вы нуждаетесь.

Как это работает

printf печатает подсказку. Никакая новая строка не добавляется.

sed вход процессов линию за линией. При отсутствии предоставления имя файла оно читает из стандартного входа, как делает read команда. В этом случае мы останавливаемся после просто первая строка (как команда чтения делает), который является что q в конце для - он выходит. В целом, sed используется для обработки нескольких строк входа, часто каждая строка в файле, но здесь мы только хотим одну строку.

И Bash и Sed являются языками, и у них обоих есть понятие команд. Каждая строка выше является единственной командой Bash, но в единственно заключенном в кавычки Sed сценарий передал sed, существует несколько команд Sed.

Первая команда Sed s/[Mm]y name is (.+)/hi, \1/. Это выполняет замену (s/). Это ищет:

  • ^ - в самом начале строки
  • [Mm] - для M или m
  • y name is - для того буквенного текста, включая конечный пробел
  • (.+) - для одного или нескольких (+) из любого символа (.). Это - то, что мы берем, чтобы быть именем пользователя. Поскольку это включается в круглые скобки, и это - первое вхождение ( в шаблоне это получено в первую группу и доступное через первую обратную ссылку, \1.

Это заменяет такой текст:

  • hi, - тот буквенный текст, включая конечный пробел
  • \1 - текст, который соответствовал .+ в шаблоне поиска

Вторая команда Sed tQ. Можно также записать это t Q. Это тестирует:

  • если операция соответствия, предпринятая предыдущим s за командой следуют.
  • Если это сделало, это пропускает к маркировке :Q, который появляется позже.

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

Третья команда Sed s/.*/I didn\x27t understand that/. Это ищет:

  • .* - Нуль или больше символов. Это всегда соответствует всей строке.

Это позволяет ничего не делать далее с входом и вместо этого заменять все это сообщением, которое мы хотим отобразить:

  • I didn - тот буквенный текст
  • \x27 - a ' символ, так как мы используем ' в оболочке для передачи целого сценария sed (иначе было бы хорошо включать литерал ' в сценарии Sed)
  • t understand that - тот буквенный текст

Маркировка :Q. Маркировки в Sed запускаются с a : но когда они переходятся к с командой Sed t (см. выше), : опущен. Можно назвать это, что Вы любите, просто изменяете все t команды, которые используют его соответственно.

Заключительная команда Sed, q. Это выходит sed. Так как с этой командой Sed всегда встречаются после обработки строки, не больше, чем одна строка когда-либо обрабатывается.

Соображения мобильности

sed команда, показанная выше, является на самом деле не портативной ко всем реализациям Sed, потому что она использует две функции, которые не являются стандартными, но вместо этого обеспечиваются конкретно GNU sed, реализацией Sed в большинстве систем GNU/Linux включая Ubuntu.

  1. Escape-последовательность \x27 означать ' (и шестнадцатеричные Escape в целом).
  2. Точки с запятой вокруг маркировок. ; обычно так же хорошо как новая строка для разделения отдельных команд Sed, но некоторые реализации не позволяют ее вокруг маркировок.

Если Вы на самом деле хотите решить эти проблемы, таким образом, можно выполнить ту же самую команду на других Ose как macOS и FreeBSD, которые не имеют GNU Sed (если Вы не устанавливаете его на них), то можно просто использовать:

sed -r 's/^[Mm]y name is (.+)/hi, \1/
tQ
s/.*/I didn'\''t understand that/
:Q
q'

Это работает, потому что оболочки стиля Границы как Bash разрешают литеральным новым строкам появляться в одинарных кавычках. Последовательность '\'' заключение в кавычки концов, a предоставлений ' это самостоятельно отдельно заключается в кавычки из-за сразу предыдущий \ символ, и затем возобновляет единственное заключение в кавычки. Это действительно все еще предполагает использование оболочки стиля Границы, хотя не обязательно bash.

Альтернатива должна использовать $' ' синтаксис, который на самом деле не стандартизирован, и не все оболочки стиля Границы, поддерживает его, хотя несколько популярных делают. Таким образом можно все еще, вероятно, записать это как истинную остроту при использовании только стандартных функций Sed, хотя я убеждаю Вас не сделать это этот путь, потому что это более сбивает с толку:

sed -r $'s/^[Mm]y name is (.+)/hi, \\1/\ntQ\n s/.*/I didn\x27t understand that/\n:Q\nq'

Кроме того, \x27 быть замененным ', \\ заменяется \ и \n заменяется новой строкой, вызывая sed получить тот же сценарий Sed как с вышеупомянутой многострочной командой, которую необходимо использовать вместо этого так или иначе.

Моя благодарность выходит в Zanna, который предложил t мог бы использоваться для этого и помог мне упростить сценарий Sed, после того как он был записан.

2
ответ дан 3 December 2019 в 06:21

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

read -p username: username ; curl -s "https://api.github.com/users/$username/repos?per_page=100" | grep -o 'git@[^"]*'
0
ответ дан 10 March 2020 в 02:57

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

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