В bash, как я могу проверить, начинается ли строка с некоторого значения? - PullRequest
624 голосов
/ 31 января 2010

Я хотел бы проверить, начинается ли строка с «узла», например, "Node001". Что-то вроде

if [ $HOST == user* ]  
  then  
  echo yes  
fi

Как я могу сделать это правильно?


Кроме того, мне нужно объединить выражения, чтобы проверить, является ли HOST либо «user1», либо начинается с «node»

if [ [[ $HOST == user1 ]] -o [[ $HOST == node* ]] ];  
then  
echo yes 
fi

> > > -bash: [: too many arguments

Как это сделать правильно?

Ответы [ 13 ]

885 голосов
/ 31 января 2010

Этот фрагмент в Расширенном руководстве по сценариям Bash говорит:

# The == comparison operator behaves differently within a double-brackets
# test than within single brackets.

[[ $a == z* ]]   # True if $a starts with a "z" (wildcard matching).
[[ $a == "z*" ]] # True if $a is equal to z* (literal matching).

Итак, у вас было почти правильно; вам нужно двойные скобки, а не одиночные скобки.


Что касается вашего второго вопроса, вы можете написать его следующим образом:

HOST=user1
if  [[ $HOST == user1 ]] || [[ $HOST == node* ]] ;
then
    echo yes1
fi

HOST=node001
if [[ $HOST == user1 ]] || [[ $HOST == node* ]] ;
then
    echo yes2
fi

Который будет эхом

yes1
yes2

Синтаксис Bash if трудно привыкнуть (IMO).

172 голосов
/ 31 января 2010

Если вы используете недавний bash (v3 +), я предлагаю использовать оператор сравнения bash regex =~, т.е.

if [[ "$HOST" =~ ^user.* ]]; then
    echo "yes"
fi

Чтобы соответствовать this or that в регулярном выражении, используйте |, т.е.

if [[ "$HOST" =~ ^user.*|^host1 ]]; then
    echo "yes"
fi

Примечание. Это правильный синтаксис регулярного выражения.

  • user* означает use и ноль или более вхождений r, поэтому use и userrrr будут совпадать.
  • user.* означает user и ноль или более вхождений любого символа, поэтому user1, userX будут совпадать.
  • ^user.* означает совпадение с шаблоном user.* в начале $ HOST.

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

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

108 голосов
/ 01 сентября 2013

Я всегда стараюсь придерживаться POSIX sh вместо использования расширений bash, поскольку одним из основных моментов написания сценариев является переносимость.(Помимо подключения программ, а не их замены)

В sh, есть простой способ проверить условие "is-prefix".

case $HOST in node*)
    your code here
esac

Учитываясколько лет, тайный и грубый sh (а bash - не лекарство: он более сложный, менее последовательный и менее переносимый), я хотел бы отметить очень хороший функциональный аспект: хотя некоторые синтаксические элементы, такие как case, созданы-в результате получаемые конструкции ничем не отличаются от любой другой работы.Они могут быть составлены таким же образом:

if case $HOST in node*) true;; *) false;; esac; then
    your code here
fi

Или даже короче

if case $HOST in node*) ;; *) false;; esac; then
    your code here
fi

Или даже короче (просто для представления ! в качестве элемента языка- но сейчас это плохой стиль)

if ! case $HOST in node*) false;; esac; then
    your code here
fi

Если вам нравится быть явным, создайте свой собственный элемент языка:

beginswith() { case $2 in "$1"*) true;; *) false;; esac; }

Разве это не очень приятно?

if beginswith node "$HOST"; then
    your code here
fi

И поскольку sh - это, в основном, только задания и списки строк (и внутренние процессы, из которых составляются задания), теперь мы можем даже выполнить небольшое функциональное программирование:

beginswith() { case $2 in "$1"*) true;; *) false;; esac; }
checkresult() { if [ $? = 0 ]; then echo TRUE; else echo FALSE; fi; }

all() {
    test=$1; shift
    for i in "$@"; do
        $test "$i" || return
    done
}

all "beginswith x" x xy xyz ; checkresult  # prints TRUE
all "beginswith x" x xy abc ; checkresult  # prints FALSE

ЭтоэлегантноНе то чтобы я рекомендовал использовать sh для чего-то серьезного - он слишком быстро нарушает требования реального мира (нет лямбда-выражений, поэтому нужно использовать строки. Но вложение вызовов функций со строками невозможно, каналы не возможны ...)

68 голосов
/ 31 января 2010

Вы можете выбрать только ту часть строки, которую хотите проверить:

if [ ${HOST:0:4} = user ]

В качестве дополнительного вопроса вы можете использовать ИЛИ :

if [[ $HOST == user1 || $HOST == node* ]]
55 голосов
/ 31 января 2010

Я предпочитаю другие методы, уже опубликованные, но некоторые люди любят использовать:

case "$HOST" in 
    user1|node*) 
            echo "yes";;
        *)
            echo "no";;
esac

Edit:

Я добавил ваши альтернативы к описанию случая выше

В вашей отредактированной версии у вас слишком много скобок. Это должно выглядеть так:

if [[ $HOST == user1 || $HOST == node* ]];
29 голосов
/ 06 мая 2016

Хотя я нахожу большинство ответов здесь совершенно правильными, многие из них содержат ненужные ошибки. Расширение параметров POSIX дает вам все, что вам нужно:

[ "${host#user}" != "${host}" ]

и

[ "${host#node}" != "${host}" ]

${var#expr} удаляет наименьший префикс, соответствующий expr из ${var}, и возвращает его. Следовательно, если ${host} не начинается с user (node), ${host#user} (${host#node}) совпадает с ${host}.

expr разрешает fnmatch() подстановочные знаки, таким образом ${host#node??} и друзья также работают.

28 голосов
/ 01 ноября 2013

, поскольку # имеет значение в bash, я нашел следующее решение.
Кроме того, мне нравится упаковывать строки с "", чтобы преодолеть пробелы и т.д.

A="#sdfs"
if [[ "$A" == "#"* ]];then
    echo "skip comment line"
fi
8 голосов
/ 06 августа 2018

Добавление чуть больше синтаксической детализации к ответу Марка Рушакова с самым высоким рангом.

Выражение

$HOST == node*

Можно также записать как

$HOST == "node"*

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

8 голосов
/ 01 февраля 2010

@ OP, для обоих ваших вопросов вы можете использовать case / esac

string="node001"
case "$string" in
  node*) echo "found";;
  * ) echo "no node";;
esac

второй вопрос

case "$HOST" in
 node*) echo "ok";;
 user) echo "ok";;
esac

case "$HOST" in
 node*|user) echo "ok";;
esac

ИЛИ Bash 4.0

case "$HOST" in
 user) ;& 
 node*) echo "ok";; 
esac
6 голосов
/ 31 января 2010
if [ [[ $HOST == user1 ]] -o [[ $HOST == node* ]] ];  
then  
echo yes 
fi

не работает, потому что все [, [[ и test ) распознают одну и ту же нерекурсивную грамматику. см. раздел УСЛОВНЫЕ ВЫРАЖЕНИЯ на вашей man-странице bash.

В стороне SUSv3 говорит:

Условная команда, полученная из KornShell (двойная скобка [[]] ), была удалена из описания языка команд оболочки в раннем предложении. Были высказаны возражения, что настоящая проблема заключается в неправильном использовании команды test ( [), и помещение ее в оболочку является неправильным способом решения проблемы. Вместо этого достаточно правильной документации и нового зарезервированного слова оболочки (! ).

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

вам нужно написать это таким образом, но test не поддерживает это:

if [ $HOST == user1 -o $HOST == node* ];  
then  
echo yes 
fi

test использует = для равенства строк, что более важно, он не поддерживает сопоставление с образцом.

case / esac имеет хорошую поддержку для сопоставления с образцом:

case $HOST in
user1|node*) echo yes ;;
esac

имеет дополнительное преимущество: он не зависит от bash, синтаксис переносим. из спецификации Single Unix, язык команд оболочки:

case word in
    [(]pattern1) compound-list;;
    [[(]pattern[ | pattern] ... ) compound-list;;] ...
    [[(]pattern[ | pattern] ... ) compound-list]
esac
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...