[string] Bash에서 문자열에 하위 문자열이 포함되어 있는지 확인하는 방법

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

needle string의 공백은 큰 따옴표로 묶어야하며 *와일드 카드는 외부에 있어야합니다. 또한 ==정규 비교 연산자가 아닌 간단한 비교 연산자가 사용됩니다 =~.


답변

정규식 접근 방식을 선호하는 경우 :

string='My string';

if [[ $string =~ "My" ]]
then
   echo "It's there!"
fi


답변

if 문을 사용할지는 확실하지 않지만 case 문을 사용하면 비슷한 효과를 얻을 수 있습니다.

case "$string" in
  *foo*)
    # Do stuff
    ;;
esac


답변

stringContain 변형 (호환 또는 대소 문자 구분)

이 스택 오버플로 답변이 대부분 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" ]; }

또는 Adrian Günter의 의견 에서 제안한대로 -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


답변

쉘 스크립팅은 언어가 아니며 명령 모음에 가깝습니다. 본능적으로이 “언어”는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 [ "$string" != "${string/foo/}" ]; then
    echo "It's 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'

매번 테스트 교체 :

[[ $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

(do는 F. Houri의 답변에 포함되었습니다)

그리고 낄낄 거림 :

echo $b|grep -q $a       12.68 user 30.86 system 3:42.40 elapsed 19% CPU !ouch!

따라서 간단한 대체 옵션은 연장 된 테스트 또는 사례에서 예측 가능합니다. 휴대용 케이스입니다.

100 만 그렙까지 배관하는 것은 예상치 못한 고통입니다! 필요없이 외부 유틸리티를 사용하는 것에 대한 기존의 규칙이 적용됩니다.