В 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"*
эффект тот же. Просто убедитесь, что подстановочный знак находится вне цитируемого текста. Если подстановочный знак внутри кавычки будут интерпретироваться буквально (т. е. не как подстановочный знак).