Я хотел бы проверить, начинается ли строка с "node", например. "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
Как это сделать правильно?
Этот фрагмент в Advanced Bash Scripting Guide говорит:
# 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
Что будет echo
yes1
yes2
Синтаксис Bash if
трудно использовать (IMO).
[[ $a == z* ]]
и [[ $a == "z*" ]]
? Другими словами: они работают по-другому? А что конкретно вы имеете в виду, когда говорите "$ a равен z *"?
Если вы используете недавний 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.Если вы не знакомы с синтаксисом регулярных выражений, попробуйте обратиться к этому ресурсу.
Обратите внимание - лучше, если вы будете задавать каждый новый вопрос как новый вопрос, это сделает stackoverflow более аккуратным и более полезным. Вы всегда можете включить ссылку на предыдущий вопрос для справки.
Я всегда стараюсь использовать POSIX sh вместо использования расширений bash, так как одним из основных моментов написания сценария является переносимость. (Помимо подключения программ, не заменяя их)
В sh, есть простой способ проверить условие "префикс".
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 для чего-то серьезного - он слишком быстро ломается от требований реального мира (нет lambdas, поэтому нужно использовать строки. Но вызов функций вложенности с помощью строк невозможно, трубы невозможны...)
case $HOST in user01 | node* ) ...
if case $HOST in node*) true;; *) false;; esac; then
я видел это здесь и там, на мой взгляд, это выглядит как будто искаженное.
Вы можете выбрать только часть строки, которую вы хотите проверить:
if [ ${HOST:0:4} = user ]
Для вашего последующего вопроса вы можете использовать OR:
if [[ $HOST == user1 || $HOST == node* ]]
${HOST:0:4}
Я предпочитаю другие уже опубликованные методы, но некоторым людям нравится использовать:
case "$HOST" in
user1|node*)
echo "yes";;
*)
echo "no";;
esac
Edit:
Я добавил ваших заместителей к описанию дела выше
В вашей отредактированной версии у вас слишком много скобок. Он должен выглядеть следующим образом:
if [[ $HOST == user1 || $HOST == node* ]];
поскольку # имеет значение в bash, я получил следующее решение.
Кроме того, мне нравится лучше упаковывать строки с помощью "" для преодоления пробелов и т.д.
A="#sdfs"
if [[ "$A" == "#"* ]];then
echo "skip comment line"
fi
blah:
похоже, это ответ!
Хотя я считаю, что большинство ответов здесь совершенно правильно, многие из них содержат ненужные базисы. Расширение параметров POSIX дает вам все, что вам нужно:
[ "${host#user}" != "${host}" ]
и
[ "${host#node}" != "${host}" ]
${var#expr}
удаляет наименьший префикс, сопоставляющий expr
с ${var}
и возвращает это. Следовательно, если ${host}
начинается не с user
(node
), ${host#user}
(${host#node}
) совпадает с ${host}
.
expr
позволяет fnmatch()
подстановочные знаки, поэтому ${host#node??}
и друзья также работают.
[[ $host == user* ]]
может быть необходим, поскольку он гораздо более читабелен, чем [ "${host#user}" != "${host}" ]
. Таким образом, при условии, что вы управляете средой, в которой выполняется скрипт (нацелены на последние версии bash
), предпочтительнее первое.
has_prefix()
и больше никогда не смотрел на это.
@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
;&
доступен только в Bash> = 4.
if [ [[ $HOST == user1 ]] -o [[ $HOST == node* ]] ];
then
echo yes
fi
не работает, потому что все [, [[и test признают ту же нерекурсивную грамматику. см. раздел УСЛОВНЫЕ ЭКСПРЕССИИ на странице bash.
В стороне, SUSv3 говорит
Условная команда, основанная на KornShell (двойная скобка [[]]), была удалена из описания языка команд оболочки в раннем предложении. Возрастали возражения, что реальной проблемой является неправильное использование тестовой команды ([), а ее размещение в оболочке - неправильный способ устранения проблемы. Вместо этого достаточно правильной документации и нового зарезервированного слова оболочки (!).
Тесты, требующие нескольких тестовых операций, могут выполняться на уровне оболочки, используя отдельные вызовы тестовой команды и логики оболочки, вместо того, чтобы использовать флаг проверки -o.
вам нужно будет записать его таким образом, но тест не поддерживает его:
if [ $HOST == user1 -o $HOST == node* ];
then
echo yes
fi
test uses = для равенства строк, что более важно, это не поддерживает соответствие шаблонов.
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
[
и test
как встроенные в Bash, так и внешние программы. Попробуйте type -a [
.
Добавление чуть более подробной информации о синтаксисе к ответу Марка Рушакова самого высокого ранга.
Выражение
$HOST == node*
Может также быть написано как
$HOST == "node"*
Эффект тот же. Просто убедитесь, что подстановочный знак находится за пределами цитируемого текста. Если подстановочный знак находится внутри кавычек, он будет интерпретирован буквально (т.е. не как подстановочный знак).
Еще одна вещь, которую вы можете сделать, это cat
из того, что вы эхом и трубкой с inline cut -c 1-1