У меня есть строка в Bash:
string="My string"
Как проверить, содержит ли она еще одну строку?
if [ $string ?? 'foo' ]; then
echo "It there!"
fi
Где ??
- мой неизвестный оператор. Использовать эхо и grep
?
if echo "$string" | grep 'foo'; then
echo "It there!"
fi
Это выглядит немного неуклюжим.
Вы можете использовать ответ Marcus (* подстановочные знаки) за пределами оператора case, если вы используете двойные скобки:
string='My long string'
if [[ $string == *"My long"* ]]; then
echo "It there!"
fi
Обратите внимание, что пробелы в игольной веревке нужно размещать между двойными кавычками, а подстановочные знаки *
должны быть снаружи.
[[: not found
. Есть идеи, что случилось? Я использую GNU Bash, версия 4.1.5 (1), на Ubuntu.
Если вы предпочитаете подход с регулярным выражением:
string='My string';
if [[ $string =~ .*My.* ]]
then
echo "It there!"
fi
Я не уверен в использовании оператора if, но вы можете получить аналогичный эффект с аргументом case:
case "$string" in
*foo*)
# Do stuff
;;
esac
Как уже было много ответов с использованием 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, 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
switche:
stringContain() { [ -z "${2##*$1*}" ] && { [ -z "$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
Вы должны помнить, что сценарий оболочки меньше языка и больше набора команд. Интуитивно вы думаете, что этот "язык" требует от вас следовать if
с помощью [
или [[
. Обе эти команды - это просто команды, которые возвращают статус выхода, указывающий на успех или неудачу (как и любая другая команда). По этой причине я использовал бы grep
, а не команду [
.
Просто выполните:
if grep -q foo <<<"$string"; then
echo "It 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 ничего не выводить, поскольку нам нужен только код возврата. <<<
заставляет оболочку расширять следующее слово и использовать его как вход в команду, однострочную версию документа <<
(я не уверен, является ли это стандартом или башизмом).
if grep -q foo <(echo somefoothing); then
Принятый ответ лучше, но поскольку есть более чем один способ сделать это, здесь другое решение:
if [ "$string" != "${string/foo/}" ]; then
echo "It there!"
fi
${var/search/replace}
имеет значение $var
, если первый экземпляр search
заменен на replace
, если он найден (он не меняет $var
). Если вы попытаетесь заменить foo
на ничего, и строка изменилась, то, очевидно, был найден foo
.
Итак, есть много полезных решений для вопроса - но что быстрее/использует наименьший ресурс?
Повторные тесты с использованием этого кадра:
/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.92user 0.06system 0:02.99elapsed 99%CPU
[ "${b/$a//}" = "$b" ] 3.16user 0.07system 0:03.25elapsed 99%CPU
[[ $b == *$a* ]] 1.85user 0.04system 0:01.90elapsed 99%CPU
case $b in *$a):;;esac 1.80user 0.02system 0:01.83elapsed 99%CPU
doContain $a $b 4.27user 0.11system 0:04.41elapsed 99%CPU
(doContain был в ответе Ф. Хури)
И для хихиканья:
echo $b|grep -q $a 12.68user 30.86system 3:42.40elapsed 19%CPU !ouch!
Таким образом, простая опция заместителя предикативно выигрывает ли в расширенном тесте или случае. Случай переносимый.
Трубопроводы до 100000 град предсказуемо болезненны! Старое правило об использовании внешних утилит не требуется.
[[ $b == *$a* ]]
.
case
выигрывает с наименьшим общим временем. Вы пропускаете звездочку после $b in *$a
. Я получаю немного более быстрые результаты для [[ $b == *$a* ]]
чем для case
с исправленной ошибкой, но, конечно, это может зависеть и от других факторов.
Это также работает:
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, поскольку один (или два) отдельных процесса будут созданы и подключены через каналы.
Как насчет этого:
text=" <tag>bmnmn</tag> "
if [[ "$text" =~ "<tag>" ]]; then
echo "matched"
else
echo "not matched"
fi
Как сказал Павел в своем сравнении производительности:
if echo "abcdefg" | grep -q "bcdef"; then
echo "String contains is true."
else
echo "String contains is not true."
fi
Это POSIX-совместимый, как "case" $string "in", предоставленный Marcus, но его немного легче читать, чем ответ на запрос в случае. Также обратите внимание, что это будет намного медленнее, чем использование аргумента case, как указал Павел, не используйте его в цикле.
Этот ответ в стеке переполнение был единственным, кто мог уловить пробелы и тире:
# For null cmd arguments checking
to_check=' -t'
space_n_dash_chars=' -'
[[ $to_check == *"$space_n_dash_chars"* ]] && echo found
Один из них:
[ $(expr $mystring : ".*${search}.*") -ne 0 ] && echo 'yes' || echo 'no'
expr
- это одна из тех утилит для швейцарских армейских ножей, которые обычно могут делать все, что вам нужно, как только вы поймете, как это сделать, но после внедрения вы никогда не сможете вспомнить, почему или как он делает то, что делает, поэтому вы никогда не трогаете его снова и надеетесь, что он никогда не перестанет делать то, что делает.
Bash4+. Примечание: не использовать кавычки вызовет проблемы, когда слова содержат пробелы и т.д. Всегда указывайте в bash IMO.
Вот несколько примеров Bash4+:
Пример 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
наслаждаться.
[[ $string == *foo* ]] && echo "It there" || echo "Couldn't find"
echo "Couldn't find
оператор echo "Couldn't find
" - это хороший прием для возврата 0 состояний выхода для этих соответствующих команд.
Мой .bash_profile и как я использовал grep если PATH включил мои 2 bin dirs, не добавляйте их
# .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'
.
Мне нравится sed.
substr="foo"
nonsub="$(echo "$string" | sed "s/$substr//")"
hassub=0 ; [ "$string" != "$nonsub" ] && hassub=1
Изменить, логика:
Использовать sed для удаления экземпляра подстроки из строки
Если новая строка отличается от старой строки, существует подстрока
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"
. Я редактирую ответ, потому что пользователь, кажется, больше не существует.
Мне часто приходилось выполнять эту функцию, поэтому я использую домашнюю функцию оболочки в моем .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
хак требуется только для очень старых оболочек.
Точное совпадение слов:
string='My long string'
exactSearch='long'
if grep -E -q "\b${exactSearch}\b" <<<${string} >/dev/null 2>&1
then
echo "It there"
fi
Попробуйте oobash - это строковая библиотека стиля 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
Я использую эту функцию (одна зависимость не включена, но очевидна). Он проходит тесты, показанные ниже. Если функция возвращает значение > 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
}
На расширение вопроса ответили здесь https://stackoverflow.com/questions/2829613/how-do-you-tell-if-a-string-contains-another-string-in-unix-shell-scripting
Это решение работает со специальными символами:
# 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*"
expr
здесь