В bash, как я могу проверить, начинается ли строка с некоторого значения?
Я хотел бы проверить, начинается ли строка с "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
Как это сделать правильно?
Ответы
Ответ 1
Этот фрагмент в 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).
Ответ 2
Если вы используете недавний 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.
Если вы не знакомы с синтаксисом регулярных выражений, попробуйте обратиться к этому ресурсу.
Обратите внимание - лучше, если вы будете задавать каждый новый вопрос как новый вопрос, это сделает работу со стеком более аккуратной и полезной. Вы всегда можете включить ссылку на предыдущий вопрос для справки.
Ответ 3
Я всегда стараюсь использовать 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 "[email protected]"; 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, поэтому нужно использовать строки. Но вызов функций вложенности с помощью строк невозможно, трубы невозможны...)
Ответ 4
Вы можете выбрать только часть строки, которую вы хотите проверить:
if [ ${HOST:0:4} = user ]
Для вашего последующего вопроса вы можете использовать OR:
if [[ $HOST == user1 || $HOST == node* ]]
Ответ 5
Я предпочитаю другие уже опубликованные методы, но некоторым людям нравится использовать:
case "$HOST" in
user1|node*)
echo "yes";;
*)
echo "no";;
esac
Edit:
Я добавил ваших заместителей к описанию дела выше
В вашей отредактированной версии у вас слишком много скобок. Он должен выглядеть следующим образом:
if [[ $HOST == user1 || $HOST == node* ]];
Ответ 6
Хотя я считаю, что большинство ответов здесь совершенно правильно, многие из них содержат ненужные базисы. Расширение параметров POSIX дает вам все, что вам нужно:
[ "${host#user}" != "${host}" ]
и
[ "${host#node}" != "${host}" ]
${var#expr}
удаляет наименьший префикс, сопоставляющий expr
с ${var}
и возвращает это. Следовательно, если ${host}
начинается не с user
(node
), ${host#user}
(${host#node}
) совпадает с ${host}
.
expr
позволяет fnmatch()
подстановочные знаки, поэтому ${host#node??}
и друзья также работают.
Ответ 7
поскольку # имеет значение в bash, я получил следующее решение.
Кроме того, мне нравится лучше упаковывать строки с помощью "" для преодоления пробелов и т.д.
A="#sdfs"
if [[ "$A" == "#"* ]];then
echo "skip comment line"
fi
Ответ 8
@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
Ответ 9
Добавление чуть более подробной информации о синтаксисе к ответу Марка Рушакова самого высокого ранга.
Выражение
$HOST == node*
Может также быть написано как
$HOST == "node"*
Эффект тот же. Просто убедитесь, что подстановочный знак находится за пределами цитируемого текста. Если подстановочный знак находится внутри кавычек, он будет интерпретирован буквально (т.е. не как подстановочный знак).
Ответ 10
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
Ответ 11
Я подправил ответ @markrushakoff, чтобы сделать его вызываемой функцией:
function yesNo {
# prompts user with $1, returns true if response starts with y or Y or is empty string
read -e -p "
$1 [Y/n] " YN
[[ "$YN" == y* || "$YN" == Y* || "$YN" == "" ]]
}
Используйте это так:
$ if yesNo "asfd"; then echo "true"; else echo "false"; fi
asfd [Y/n] y
true
$ if yesNo "asfd"; then echo "true"; else echo "false"; fi
asfd [Y/n] Y
true
$ if yesNo "asfd"; then echo "true"; else echo "false"; fi
asfd [Y/n] yes
true
$ if yesNo "asfd"; then echo "true"; else echo "false"; fi
asfd [Y/n]
true
$ if yesNo "asfd"; then echo "true"; else echo "false"; fi
asfd [Y/n] n
false
$ if yesNo "asfd"; then echo "true"; else echo "false"; fi
asfd [Y/n] ddddd
false
Вот более сложная версия, которая предусматривает указанное значение по умолчанию:
function toLowerCase {
echo "$1" | tr '[:upper:]' '[:lower:]'
}
function yesNo {
# $1: user prompt
# $2: default value (assumed to be Y if not specified)
# Prompts user with $1, using default value of $2, returns true if response starts with y or Y or is empty string
local DEFAULT=yes
if [ "$2" ]; then local DEFAULT="$( toLowerCase "$2" )"; fi
if [[ "$DEFAULT" == y* ]]; then
local PROMPT="[Y/n]"
else
local PROMPT="[y/N]"
fi
read -e -p "
$1 $PROMPT " YN
YN="$( toLowerCase "$YN" )"
{ [ "$YN" == "" ] && [[ "$PROMPT" = *Y* ]]; } || [[ "$YN" = y* ]]
}
Используйте это так:
$ if yesNo "asfd" n; then echo "true"; else echo "false"; fi
asfd [y/N]
false
$ if yesNo "asfd" n; then echo "true"; else echo "false"; fi
asfd [y/N] y
true
$ if yesNo "asfd" y; then echo "true"; else echo "false"; fi
asfd [Y/n] n
false
Ответ 12
grep
Забывая о производительности, это POSIX и выглядит лучше, чем решения для case
:
mystr="abcd"
if printf '%s' "$mystr" | grep -Eq '^ab'; then
echo matches
fi
Объяснение:
Ответ 13
Еще одна вещь, которую вы можете сделать, это cat
из того, что вы эхом и трубкой с inline cut -c 1-1