Я хочу написать функцию, которая проверяет, var
начинается ли заданная переменная, скажем, с любого слова из заданного списка строк. Этот список не изменится.
Для примера представим, что я хочу проверить, var
начинается ли строка с aa
, abc
или 3@3
.
Более того, я хочу проверить, var
содержит ли символ >
.
Допустим, эта функция называется check_func
. Мое предполагаемое использование выглядит примерно так:
if check_func "$var"; then
do stuff
fi
Например, он должен «делать вещи» для aardvark
, abcdef
и .[email protected]
12>5
я виделэтот ТАК вопросгде пользователь предоставляет часть работы:
beginswith() { case $2 in "$1"*) true;; *) false;; esac; }
Моя идея заключается в том, что я бы перебрал список, упомянутый выше, и использовал эту функцию. Моя трудность заключается в том, что я не понимаю, как именно следует выполнить выход (или что-то, что заменяет возврат), чтобы это сработало.
решение1
check_prefixes () {
value=$1
for prefix in aa abc 3@3; do
case $value in
"$prefix"*) return 0
esac
done
return 1
}
check_contains_gt () {
value=$1
case $value in
*">"*) return 0
esac
return 1
}
var='aa>'
if check_prefixes "$var" && check_contains_gt "$var"; then
printf '"%s" contains ">" and starts with one of the prefixes\n' "$var"
fi
Я разделил тесты на две функции. Оба используют case ... esac
и возвращают успех (ноль), как только это может быть определено. Если ничего не совпадает, возвращается неудача (1).
Чтобы сделать список префиксов более динамическим, можно было бы записать первую функцию как
check_prefixes () {
value=$1
shift
for prefix do
case $value in
"$prefix"*) return 0
esac
done
return 1
}
(значение для проверки — это первый аргумент, который мы сохраняем в списке аргументов функции, value
а затем удаляем из него; затем мы перебираем оставшиеся аргументы), а затем вызываем его какshift
check_prefixes "$var" aa abc 3@3
Вторую функцию можно изменить аналогичным образом, на
check_contains () {
value=$1
shift
case $value in
*"$1"*) return 0
esac
return 1
}
(для проверки некоторой произвольной подстроки) или
check_contains_oneof () {
value=$1
shift
for substring do
case $value in
*"$substring"*) return 0
esac
done
return 1
}
(для проверки любой из нескольких подстрок)
решение2
Для Баша:
Используя свойства регулярных выражений, вы можете писать start
с помощью ничего ^
и contain
без ничего.
Список регулярных выражений для проверкиначинатьс aa
abc
или 3@3
исодержит >
является:
^aa ^abc ^3@3 >
Сделай этоправильнозаключить список в кавычки и попросить bash использовать регулярные выражения ( =~
):
check_func() {
matched=1
for test_regex in '^aa' '^abc' '^3@3' '>'; do
if [[ $var =~ $test_regex ]] ; then
matched=0
break
fi
done
return "$matched"
}
var='aaIsAMatch'
if check_func; then
echo "A match was found"
fi
Функция жестко закодировала список совпадений и имя переменной.
Передача списка регулярных выражений в переменной массива и значения для проверки в первом аргументе:
check_func() {
local matched; matched=1
for t in "${test_regex[@]}"; do
[[ $1 =~ $t ]] && { matched=0; break; }
done
return "$matched"
}
test_regex=('^aa' '^abc' '^3@3' '>')
if check_func 'aaIsAMatch'; then
echo "A match was found"
fi
Функцию можно было бы усовершенствовать, используя в качестве первого аргумента имя переменной (вместо значения).
posix
Поскольку в оболочках posix нет регулярных выражений, а единственный способ проверки — это оператор case, мы должны использовать оператор case. К сожалению, для старых оболочек ([расширенные globs недоступны][1]) мы должны зацикливаться, чтобы выполнить все проверки. И globs должны быть:
'aa*' 'abc*' '3@3*' '*>*'
Пример скрипта, который проверяет несколько входных строк на соответствие нескольким глобам:
check_func() { :
matched=1
value=$1; shift
for t in "$@"; do
case $value in $t) matched=0; #break;; esac
echo "matched $value with $t"
;;
esac
done
return "$matched"
}
for var in abdg wabcde aadef abcde 3@3hello hmm3@3hell 'we>we' 'a>dfff' 'dfd>' 'a> de' 'a*> fg'; do
if check_func "$var" 'aa*' 'abc*' '3@3*' '*>*'; then
echo "========A match was found for \"$var\""
fi
done
Более простая версия функции, которая точно соответствует вашему запросу:
check_func() { :
matched=1
value=$1; shift
for t in "$@"; do
case $value in $t) matched=0; break;; esac
done
return "$matched"
}
решение3
Вот что case
делает оператор: принимает второй параметр функции ( $2
). Если он соответствует шаблону "$1"*
, то есть первый аргумент функции, за которым следует что-либо, то выполнить true
и завершить case
оператор. true
ничего не делает и возвращает статус 0. В противном случае, если он соответствует *
, то есть что-либо, то выполнить false
и завершить case
оператор. false
ничего не делает и возвращает статус 1. Таким образом, case
оператор имеет статус 0, если второй параметр начинается с первого параметра, и 1 в противном случае. Поскольку это последний (и единственный) оператор в функции, функция возвращает 0, если второй параметр начинается с первого параметра, и 1 в противном случае.
Условные операторы, такие как if
в оболочке, считают оператор истинным, если он возвращает 0, и ложным в противном случае. Следовательно, if beginswith "$var" "string"; then echo yes; else echo no; fi
печатает yes
, если значение var
начинается с, string
а no
в противном случае.
Есть несколько альтернативных способов написать эту функцию. Например, автор мог бы использовать return 0
or return 1
вместо true
and false
, так как они являются последним оператором в функции. Способ написания функции позволяет использовать ее тело напрямую, не оборачивая его в функцию, просто заменив ссылки на параметры функции ( $1
и $2
) на любые строки, с которыми вы хотите работать.
Чтобы разрешить несколько префиксов, переберите их в цикле. Как только вы найдете соответствующий префикс, вернитесь из функции с истинным статусом (0). Если ни один из префиксов не совпадает, верните ложный статус (обычно 1).
# begins_with STRING PREFIX1 PREFIX2...
# Test if STRING starts with any of PREFIX1, PREFIX2, ...
begins_with () {
string=$1
shift
for prefix in "$@"; do
case "$string" in
"$prefix"*) return 0;;
esac
done
return 1
}
if begins_with "$var" 'aa' 'abc' '3@3'; then
echo "The value starts with one of the permitted prefixes"
fi
Для проверки суффикса используйте шаблон *"$suffix"
вместо "$prefix"*
. Для проверки подстроки используйте *"$substring"*
. Обратите внимание, что двойные кавычки здесь необходимы, иначе переменная будет интерпретироваться как шаблон. Например:
suffix='?'
case "$var" in
*"$suffix") echo "The value of var ends with a question mark";;
esac
case "$var" in
*$suffix) echo "The value of var is not empty";;
esac
решение4
Пересмотрено на основе разъяснения вопроса: Это менее элегантно (и гораздо менее гибко), но более компактно, чем другие ответы.
check_func() {
case "$1" in
( aa* | abc* | 3@3* | *">"*)
return 0
esac
return 1
}
Это возвращает true для aardvark
, abcdef
, [email protected]
и 12>5
. И, конечно же, также aard>vark
, abc<def>ghi
и 3@3>3
.