У меня есть строка в Bash:
string="My string"
Как я могу проверить, содержит ли она другую строку?
if [ $string ?? 'foo' ]; then
echo "It's there!"
fi
Где ??
мой неизвестный оператор. Я использую эхо и grep
?
if echo "$string" | grep 'foo'; then
echo "It's there!"
fi
Это выглядит немного неуклюже.
Вы также можете использовать ответ Маркуса (* подстановочные знаки) вне оператора case, если вы используете двойные скобки:
string='My long string'
if [[ $string == *"My long"* ]]; then
echo "It's there!"
fi
Обратите внимание, что пробелы в строке иглы должны быть помещены между двойными кавычками, а *
подстановочные знаки должны быть снаружи. Также обратите внимание, что используется простой оператор сравнения (т.е. ==
), а не оператор регулярного выражения =~
.
#!/bin/sh
. Попробуй #!/bin/bash
вместо этого. [[
. Смотрите ideone.com/ZSy1gZЯ не уверен в использовании оператора if, но вы можете получить аналогичный эффект с помощью оператора case:
case "$string" in
*foo*)
# Do stuff
;;
esac
[[ $string == *foo* ]]
также работает в некоторых POSIX-совместимых версиях sh (например, /usr/xpg4/bin/sh
в Solaris 10) и ksh (> = 88)[[
... переключатель корпуса работал! Принятый ответ лучше, но, поскольку есть несколько способов сделать это, вот другое решение:
if [ "$string" != "${string/foo/}" ]; then
echo "It's there!"
fi
${var/search/replace}
это $var
с первым экземпляром search
заменено replace
, если он найден (это не меняет $var
). Если вы попытаетесь заменить foo
ничем, а строка изменилась, то, очевидно, foo
был найден.
Если вы предпочитаете подход регулярных выражений:
string='My string';
if [[ $string =~ "My" ]]
then
echo "It's there!"
fi
=~
Оператор уже ищет всю строку на матч; что .*
«s здесь посторонний. Кроме того, кавычки, как правило, предпочтительнее обратной косой черты:[[ $string =~ "My s" ]]
E14)
. Вероятно, лучше присвоить переменную (используя кавычки), а затем сравнить. Как это:re="My s"; if [[ $string =~ $re ]]
if [[ ! "abc" =~ "d" ]]
верно. number=2; if [[ "1, 2, 4, 5" = *${number}* ]]; then echo forward $number; fi; if [[ *${number}* = "1, 2, 4, 5" ]]; then echo backwards $number; fi;
Вы должны помнить, что сценарии оболочки - это не столько язык, сколько набор команд. Инстинктивно вы думаете, что этот «язык» требует, чтобы вы следовали if
с a [
или a [[
. Обе они являются просто командами, которые возвращают состояние выхода, указывающее на успех или неудачу (как и любая другая команда). По этой причине я бы использовал grep
, а не [
команду.
Просто делать:
if grep -q foo <<<"$string"; then
echo "It's there"
fi
Теперь, когда вы рассматриваете if
тестирование состояния выхода команды, которая следует за ней (завершается точкой с запятой), почему бы не пересмотреть источник тестируемой строки?
## Instead of this
filetype="$(file -b "$1")"
if grep -q "tar archive" <<<"$filetype"; then
#...
## Simply do this
if file -b "$1" | grep -q "tar archive"; then
#...
-q
Опция делает Grep не выводить ничего, как мы только хотим , код возврата. <<<
заставляет оболочку развернуть следующее слово и использовать его в качестве входных данных для команды, однострочной версии <<
документа здесь (я не уверен, является ли это стандартным или Bashism).
if grep -q foo <(echo somefoothing); then
echo
это непереносимо, если вы передаете переменную, используйте printf '%s' "$string
вместо этого. grep -q foo <<<"$mystring"
высока : выполнение 1 вилки, это башизм и echo $mystring | grep -q foo
2 вилки (одна для трубы, а вторая для бега /path/to/grep
)echo
без флагов может по-прежнему иметь непредвиденные проблемы с переносимостью, если строка аргумента содержит последовательности с обратной косой чертой. echo "nope\c"
ожидается, что на некоторых платформах будет работать как echo -e "nope"
на некоторых других. printf '%s' "nope"
противprintf '%s\n' 'nope\c'
grep -q
полезно для этого.
То же самое с использованием awk
:
string="unix-bash 2389"
character="@"
printf '%s' "$string" | awk -vc="$character" '{ if (gsub(c, "")) { print "Found" } else { print "Not Found" } }'
Вывод:
не обнаружена
string="unix-bash 2389"
character="-"
printf '%s' "$string" | awk -vc="$character" '{ if (gsub(c, "")) { print "Found" } else { print "Not Found" } }'
Вывод:
Нашел
Оригинальный источник: http://unstableme.blogspot.com/2008/06/bash-search-letter-in-string-awk.html
echo
является непереносимым, вы должны использовать printf '%s' "$string"
вместо этого. Я редактирую ответ, потому что пользователь, кажется, больше не существует. Как насчет этого:
text=" <tag>bmnmn</tag> "
if [[ "$text" =~ "<tag>" ]]; then
echo "matched"
else
echo "not matched"
fi
Попробуйте ообаш.
Это библиотека строк в стиле OO для Bash 4. Она поддерживает немецкие умлауты. Это написано на Bash.
Многие функции: -base64Decode
, -base64Encode
, -capitalize
, -center
, -charAt
, -concat
, -contains
, -count
, -endsWith
, -equals
, -equalsIgnoreCase
, -reverse
, -hashCode
, -indexOf
, -isAlnum
, -isAlpha
, -isAscii
, -isDigit
, -isEmpty
, -isHexDigit
, -isLowerCase
, -isSpace
, -isPrintable
, -isUpperCase
, -isVisible
, -lastIndexOf
, -length
, -matches
, -replaceAll
, -replaceFirst
, -startsWith
, -substring
, -swapCase
, -toLowerCase
, -toString
, -toUpperCase
, -trim
, и -zfill
.
Посмотрите на содержащийся пример:
[Desktop]$ String a testXccc
[Desktop]$ a.contains tX
true
[Desktop]$ a.contains XtX
false
Один:
[ $(expr $mystring : ".*${search}.*") -ne 0 ] && echo 'yes' || echo 'no'
expr
это одна из тех утилит для швейцарских армейских ножей, которые обычно могут делать все, что вам нужно, как только вы поймете, как это сделать, но после внедрения вы никогда не сможете вспомнить, почему или как он делает то, что делает, так что вы никогда не трогай его снова и надейся, что он никогда не перестанет делать то, что делает. expr
, в редких случаях, когда переносимость не позволяет использовать bash (например, несовместимое поведение в более старых версиях), tr (несовместимый везде) или sed (иногда слишком медленный). Но из личного опыта, когда бы я ни перечитывал эти expr
-измы, я должен вернуться на страницу руководства. Итак, я бы просто прокомментировал, что каждое использование expr
будет прокомментировано ...expr
и test
были реализованы для их выполнения. В наше время обычно существуют лучшие инструменты, многие из которых встроены в любую современную оболочку. Я думаю test
, все еще там висит, но, кажется, никто не пропал expr
. Я обнаружил, что эта функциональность нужна довольно часто, поэтому я использую самодельную функцию оболочки в своем .bashrc
подобии, которая позволяет мне использовать ее так часто, как мне нужно, с легко запоминающимся именем:
function stringinstring()
{
case "$2" in
*"$1"*)
return 0
;;
esac
return 1
}
Чтобы проверить $string1
, содержится ли (скажем, abc ) в $string2
(скажем, 123abcABC ), мне просто нужно запустить stringinstring "$string1" "$string2"
и проверить, например, возвращаемое значение
stringinstring "$str1" "$str2" && echo YES || echo NO
x
взлом требуется только для очень старых оболочек. Это также работает:
if printf -- '%s' "$haystack" | egrep -q -- "$needle"
then
printf "Found needle in haystack"
fi
И отрицательный тест это:
if ! printf -- '%s' "$haystack" | egrep -q -- "$needle"
then
echo "Did not find needle in haystack"
fi
Я полагаю, что этот стиль немного более классический - меньше зависит от особенностей оболочки Bash.
--
Аргумент чисто POSIX паранойя, используется для защищенных от входных строк , подобных опции, таких как --abc
или -a
.
Примечание. В тесном цикле этот код будет работать намного медленнее, чем при использовании внутренних функций оболочки Bash, поскольку один (или два) отдельных процесса будут создаваться и соединяться через каналы.
echo
является непереносимым, вы должны использовать printf '%s' "$haystack
вместо этого. echo
всего, кроме буквального текста без escape-символов, которые не начинаются с a -
. Это может работать для вас, но это не портативно. Даже bash echo
будет вести себя по-разному в зависимости от того, установлена ли xpg_echo
опция. PS: я забыл закрыть двойную кавычку в моем предыдущем комментарии. --
не указан в спецификации POSIX дляprintf
, но вы должны использовать в printf '%s' "$anything"
любом случае, чтобы избежать проблем, если $anything
содержит %
символ. Этот ответ переполнения стека был единственным, кто ловил пробел и тире символов:
# For null cmd arguments checking
to_check=' -t'
space_n_dash_chars=' -'
[[ $to_check == *"$space_n_dash_chars"* ]] && echo found
Поскольку эти ответы о переполнении стека в основном рассказывают о Bash , я разместил независимую от регистра функцию Bash в самом конце этого поста ...
Во всяком случае, есть мой
Совместимый ответ
Поскольку уже есть много ответов, использующих специфичные для Bash функции, есть способ работать с более слабыми оболочками, такими как BusyBox :
[ -z "${string##*$reqsubstr*}" ]
На практике это может дать:
string='echo "My string"'
for reqsubstr in 'o "M' 'alt' 'str';do
if [ -z "${string##*$reqsubstr*}" ] ;then
echo "String '$string' contain substring: '$reqsubstr'."
else
echo "String '$string' don't contain substring: '$reqsubstr'."
fi
done
Это было протестировано в Bash, Dash , KornShell ( ksh
) и ash (BusyBox), и результат всегда:
String 'echo "My string"' contain substring: 'o "M'.
String 'echo "My string"' don't contain substring: 'alt'.
String 'echo "My string"' contain substring: 'str'.
В одну функцию
По словам @EeroAaltonen, здесь есть версия того же демо, протестированная под теми же оболочками:
myfunc() {
reqsubstr="$1"
shift
string="$@"
if [ -z "${string##*$reqsubstr*}" ] ;then
echo "String '$string' contain substring: '$reqsubstr'.";
else
echo "String '$string' don't contain substring: '$reqsubstr'."
fi
}
Потом:
$ myfunc 'o "M' 'echo "My String"'
String 'echo "My String"' contain substring 'o "M'.
$ myfunc 'alt' 'echo "My String"'
String 'echo "My String"' don't contain substring 'alt'.
Обратите внимание: вы должны экранировать или заключить в двойные кавычки и / или двойные кавычки:
$ myfunc 'o "M' echo "My String"
String 'echo My String' don't contain substring: 'o "M'.
$ myfunc 'o "M' echo \"My String\"
String 'echo "My String"' contain substring: 'o "M'.
Простая функция
Это было протестировано под BusyBox, Dash и, конечно же, Bash:
stringContain() { [ -z "${2##*$1*}" ]; }
Это все, ребята!
То теперь:
$ if stringContain 'o "M3' 'echo "My String"';then echo yes;else echo no;fi
no
$ if stringContain 'o "M' 'echo "My String"';then echo yes;else echo no;fi
yes
... Или если отправленная строка может быть пустой, как указано @Sjlver, функция станет такой:
stringContain() { [ -z "${2##*$1*}" ] && [ -z "$1" -o -n "$2" ]; }
или как предложено в комментарии Адриана Гюнтера , избегая -o
переключателей:
stringContain() { [ -z "${2##*$1*}" ] && { [ -z "$1" ] || [ -n "$2" ];};}
Финальная (простая) функция:
И инвертировать тесты, чтобы сделать их потенциально быстрее:
stringContain() { [ -z "$1" ] || { [ -z "${2##*$1*}" ] && [ -n "$2" ];};}
С пустыми строками:
$ if stringContain '' ''; then echo yes; else echo no; fi
yes
$ if stringContain 'o "M' ''; then echo yes; else echo no; fi
no
Независимо от регистра (только Bash!)
Для проверки строк без учета регистра просто конвертируйте каждую строку в нижний регистр:
stringContain() {
local _lc=${2,,}
[ -z "$1" ] || { [ -z "${_lc##*${1,,}*}" ] && [ -n "$2" ] ;} ;}
Проверьте:
stringContain 'o "M3' 'echo "my string"' && echo yes || echo no
no
stringContain 'o "My' 'echo "my string"' && echo yes || echo no
yes
if stringContain '' ''; then echo yes; else echo no; fi
yes
if stringContain 'o "M' ''; then echo yes; else echo no; fi
no
string_contains() { [ -z "${2##*$1*}" ] && [ -n "$2" -o -z "$1" ]; }
заключительной мыслью: содержит ли пустая строка пустую строку? Версия выше вещи да (из-за -o -z "$1"
части). Таким образом, есть много полезных решений вопроса - но какой из них самый быстрый / использует наименьшее количество ресурсов?
Повторные тесты с использованием этого кадра:
/usr/bin/time bash -c 'a=two;b=onetwothree; x=100000; while [ $x -gt 0 ]; do TEST ; x=$(($x-1)); done'
Замена TEST каждый раз:
[[ $b =~ $a ]] 2.92 user 0.06 system 0:02.99 elapsed 99% CPU
[ "${b/$a//}" = "$b" ] 3.16 user 0.07 system 0:03.25 elapsed 99% CPU
[[ $b == *$a* ]] 1.85 user 0.04 system 0:01.90 elapsed 99% CPU
case $b in *$a):;;esac 1.80 user 0.02 system 0:01.83 elapsed 99% CPU
doContain $a $b 4.27 user 0.11 system 0:04.41 elapsed 99%CPU
(doContain был в ответе Ф. Хури)
И для хихиканья:
echo $b|grep -q $a 12.68 user 30.86 system 3:42.40 elapsed 19% CPU !ouch!
Таким образом, опция простого замещения предсказуемо выигрывает либо в расширенном тесте, либо в случае. Чехол переносной.
Выпадение до 100000 greps предсказуемо больно! Старое правило об использовании внешних утилит без необходимости сохраняется.
[[ $b == *$a* ]]
. case
выигрывает с наименьшим общим временем. Вы пропустили звездочку после того, $b in *$a
как. Я получаю немного более быстрые результаты, [[ $b == *$a* ]]
чем за case
исправленную ошибку, но, конечно, это может зависеть и от других факторов. [[ $b == *$a* ]]
быстрый и case
почти такой же быстрый (и приятно POSIX-совместимый). Как Павел упоминал в своем сравнении производительности:
if echo "abcdefg" | grep -q "bcdef"; then
echo "String contains is true."
else
echo "String contains is not true."
fi
Это соответствует POSIX, как 'case' $ string 'в' ответе, предоставленном Маркусом , но его легче читать, чем ответ оператора case. Также обратите внимание, что это будет намного медленнее, чем использование оператора case. Как указывал Пол, не используйте это в цикле.
[[ $string == *foo* ]] && echo "It's there" || echo "Couldn't find"
echo "Couldn't find
оператор в конце является хорошим трюком для возврата 0 состояний выхода для этих соответствующих команд. || echo "Couldn't find"
вы вернете состояние выхода из ошибки, если совпадения не будет, что может не понадобиться, если вы запускаете конвейер CI, например, где вы хотите, чтобы все команды возвращались статусы выхода без ошибокМне нравится Сед.
substr="foo"
nonsub="$(echo "$string" | sed "s/$substr//")"
hassub=0 ; [ "$string" != "$nonsub" ] && hassub=1
Изменить, Логика:
Используйте sed, чтобы удалить экземпляр подстроки из строки
Если новая строка отличается от старой, существует подстрока
Точное совпадение слов:
string='My long string'
exactSearch='long'
if grep -E -q "\b${exactSearch}\b" <<<${string} >/dev/null 2>&1
then
echo "It's there"
fi
Мой файл .bash_profile и как я использовал grep:
Если переменная окружения PATH включает мои две bin
директории, не добавляйте их,
# .bash_profile
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
U=~/.local.bin:~/bin
if ! echo "$PATH" | grep -q "home"; then
export PATH=$PATH:${U}
fi
grep -q -E 'pattern1|...|patternN'
. Я использую эту функцию (одна зависимость не включена, но очевидна). Он проходит испытания, показанные ниже. Если функция возвращает значение> 0, то строка была найдена. Вы можете так же легко вернуть 1 или 0 вместо этого.
function str_instr {
# Return position of ```str``` within ```string```.
# >>> str_instr "str" "string"
# str: String to search for.
# string: String to search.
typeset str string x
# Behavior here is not the same in bash vs ksh unless we escape special characters.
str="$(str_escape_special_characters "${1}")"
string="${2}"
x="${string%%$str*}"
if [[ "${x}" != "${string}" ]]; then
echo "${#x} + 1" | bc -l
else
echo 0
fi
}
function test_str_instr {
str_instr "(" "'foo@host (dev,web)'" | assert_eq 11
str_instr ")" "'foo@host (dev,web)'" | assert_eq 19
str_instr "[" "'foo@host [dev,web]'" | assert_eq 11
str_instr "]" "'foo@host [dev,web]'" | assert_eq 19
str_instr "a" "abc" | assert_eq 1
str_instr "z" "abc" | assert_eq 0
str_instr "Eggs" "Green Eggs And Ham" | assert_eq 7
str_instr "a" "" | assert_eq 0
str_instr "" "" | assert_eq 0
str_instr " " "Green Eggs" | assert_eq 6
str_instr " " " Green " | assert_eq 1
}
Bash 4+ примеров. Примечание: не использование кавычек приведет к проблемам, когда слова содержат пробелы и т. Д. Всегда заключайте в Bash, IMO.
Вот несколько примеров Bash 4+:
Пример 1, проверьте «да» в строке (без учета регистра):
if [[ "${str,,}" == *"yes"* ]] ;then
Пример 2, проверьте «да» в строке (без учета регистра):
if [[ "$(echo "$str" | tr '[:upper:]' '[:lower:]')" == *"yes"* ]] ;then
Пример 3, проверьте «да» в строке (с учетом регистра):
if [[ "${str}" == *"yes"* ]] ;then
Пример 4, проверьте «да» в строке (с учетом регистра):
if [[ "${str}" =~ "yes" ]] ;then
Пример 5, точное совпадение (с учетом регистра):
if [[ "${str}" == "yes" ]] ;then
Пример 6, точное совпадение (без учета регистра):
if [[ "${str,,}" == "yes" ]] ;then
Пример 7, точное совпадение:
if [ "$a" = "$b" ] ;then
Пример 8, подстановочный знак .ext (без учета регистра):
if echo "$a" | egrep -iq "\.(mp[3-4]|txt|css|jpg|png)" ; then
Наслаждаться.
Расширение вопроса, на который здесь дан ответ Как узнать, содержит ли строка другую строку в POSIX sh? :
Это решение работает со специальными символами:
# contains(string, substring)
#
# Returns 0 if the specified string contains the specified substring,
# otherwise returns 1.
contains() {
string="$1"
substring="$2"
if echo "$string" | $(type -p ggrep grep | head -1) -F -- "$substring" >/dev/null; then
return 0 # $substring is in $string
else
return 1 # $substring is not in $string
fi
}
contains "abcd" "e" || echo "abcd does not contain e"
contains "abcd" "ab" && echo "abcd contains ab"
contains "abcd" "bc" && echo "abcd contains bc"
contains "abcd" "cd" && echo "abcd contains cd"
contains "abcd" "abcd" && echo "abcd contains abcd"
contains "" "" && echo "empty string contains empty string"
contains "a" "" && echo "a contains empty string"
contains "" "a" || echo "empty string does not contain a"
contains "abcd efgh" "cd ef" && echo "abcd efgh contains cd ef"
contains "abcd efgh" " " && echo "abcd efgh contains a space"
contains "abcd [efg] hij" "[efg]" && echo "abcd [efg] hij contains [efg]"
contains "abcd [efg] hij" "[effg]" || echo "abcd [efg] hij does not contain [effg]"
contains "abcd *efg* hij" "*efg*" && echo "abcd *efg* hij contains *efg*"
contains "abcd *efg* hij" "d *efg* h" && echo "abcd *efg* hij contains d *efg* h"
contains "abcd *efg* hij" "*effg*" || echo "abcd *efg* hij does not contain *effg*"
contains "-n" "n"
здесь не работает, потому echo -n
что проглотит -n
как опцию! printf "%s\n" "$string"
Вместо этого популярным решением является использование . Поскольку вопрос POSIX / BusyBox закрыт без предоставления правильного ответа (IMHO), я выложу ответ здесь.
Кратчайший ответ:
[ ${_string_##*$_substring_*} ] || echo Substring found!
или
[ "${_string_##*$_substring_*}" ] || echo 'Substring found!'
Обратите внимание , что двойной хэш является обязательным с некоторыми оболочками ( ash
). Выше будет оцениваться, [ stringvalue ]
когда подстрока не найдена. Это не возвращает ошибку. Когда подстрока найдена, результат является пустым, и он оценивает [ ]
. Это выдаст код ошибки 1, так как строка полностью заменена (из-за *
).
Самый короткий более распространенный синтаксис:
[ -z "${_string_##*$_substring_*}" ] && echo 'Substring found!'
или
[ -n "${_string_##*$_substring_*}" ] || echo 'Substring found!'
Другой:
[ "${_string_##$_substring_}" != "$_string_" ] && echo 'Substring found!'
или
[ "${_string_##$_substring_}" = "$_string_" ] || echo 'Substring found!'
Обратите внимание на один знак равенства!
msg="message"
function check {
echo $msg | egrep [abc] 1> /dev/null
if [ $? -ne 1 ];
then
echo "found"
else
echo "not found"
fi
}
check
Это найдет любое вхождение a или b или c
Общий пример стога сена иглы следующий с переменными
#!/bin/bash
needle="a_needle"
haystack="a_needle another_needle a_third_needle"
if [[ $haystack == *"$needle"* ]]; then
echo "needle found"
else
echo "needle NOT found"
fi
case $string in (*foo*)
# Do stuff
esac
Это тот же ответ, что и https://stackoverflow.com/a/229585/11267590 . Но простой стиль, а также POSIX-совместимый.
expr
команду здесь