В bash, как я могу проверить, начинается ли строка с некоторого значения?

Я хотел бы проверить, начинается ли строка с "node", например"node001". Что-то вроде

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

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


мне Далее нужно объединить выражения, чтобы проверить, является ли хост " user1 "или начинается с"node"

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

> > > -bash: [: too many arguments

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

11 ответов


этот фрагмент на Расширенный 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
Баша!--3--> синтаксис трудно привыкнуть (IMO).

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

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

в матче this or that в regex использовать |, то есть

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

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

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

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

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


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

в 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  in ""*) true;; *) false;; esac; }

разве это не совсем так мило?

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

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

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

all() {
    test=; 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 для чего-то серьезного-он слишком быстро ломается на реальных требованиях (нет лямбд, поэтому нужно использовать строки. Но вызовы функций вложенности со строками невозможны, каналы невозможны...)


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

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

для вашего последующего вопроса Вы можете использовать или:

if [[ $HOST == user1 || $HOST == node* ]]

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

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

Edit:

я добавил ваши альтернативы к заявлению case выше

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

if [[ $HOST == user1 || $HOST == node* ]];

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

A="#sdfs"
if [[ "$A" == "#"* ]];then
    echo "skip comment line"
fi

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

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

и

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

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

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


@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

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

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

в стороне, SUSv3 говорит

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

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

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

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

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

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

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

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

case word in
    [(]pattern1) compound-list;;
    [[(]pattern[ | pattern] ... ) compound-list;;] ...
    [[(]pattern[ | pattern] ... ) compound-list]
esac

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

выражение

$HOST == node*

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

$HOST == "node"*

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


еще одна вещь, которую вы можете сделать, это cat из того, что вы эхо и трубы с inline cut -c 1-1