POSIX sh에 문자열에 다른 문자열이 포함되어 있는지 어떻게 알 수 있습니까?


136

다른 문자열 안에 문자열이 있으면 다양한 논리를 수행하는 Unix 쉘 스크립트를 작성하고 싶습니다. 예를 들어, 특정 폴더에있는 경우 분기합니다. 누군가 이것을 달성하는 방법을 말해 줄 수 있습니까? 가능하다면 나는 이것을 쉘 특정이 아닌 것으로 만들고 싶습니다 (즉, bash만이 아닙니다). 다른 방법이 없다면 그렇게 할 수 있습니다.

#!/usr/bin/env sh

if [ "$PWD" contains "String1" ]
then
    echo "String1 present"
elif [ "$PWD" contains "String2" ]
then
    echo "String2 present"
else
    echo "Else"
fi

2
나는 이것이 오래되었다는 것을 알고 있지만 다음 방문자에게 유의해야 할 몇 가지 사항이 있습니다. (1) 일반적으로 환경 및 쉘 내부 변수에 SNAKE_CASE 변수 이름을 예약하는 것이 좋습니다. (2) 설정 CURRENT_DIR이 중복됩니다. 당신은 사용할 수 있습니다 $PWD.
nyuszika7h

답변:


162

여기 또 다른 해결책이 있습니다. 이것은 사용 POSIX 서브 스트링 파라미터 확장 은, 대쉬, 콘 셸 (KSH) Z 쉘 (zsh을) 등 배시 작동하므로

test "${string#*$word}" != "$string" && echo "$word found in $string"

몇 가지 예가 포함 된 기능화 된 버전 :

# contains(string, substring)
#
# Returns 0 if the specified string contains the specified substring,
# otherwise returns 1.
contains() {
    string="$1"
    substring="$2"
    if test "${string#*$substring}" != "$string"
    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"

3
하위 문자열에 백 슬래시가 포함되어 있으면 작동하지 않습니다. 평소처럼 substring="$( printf '%q' "$2" )"하루를 저장합니다.
Egor Tensin

이것은 잘못된 하위 기준과도 일치합니다. string = "aplha betaone"substring = "beta"입니다. 내가 잘못 생각하는 반면 그것은 베타 베타 dbeta와 일치합니다.
rajeev

1
무엇에 대한 와일드 카드를 사용 ? [[ $haystack == *"My needle"* ]]
Pablo A

4
문제는 이중 대괄호가 POSIX가 아니기 때문에 @Pablo라는 질문의 전제였습니다.
Rob Kennedy

1
와 같은 특수 문자에는 작동하지 않습니다 []. 내 답변 stackoverflow.com/a/54490453/712666을 참조하십시오 .
Alex Skrypnyk

85

순수한 POSIX 쉘 :

#!/bin/sh
CURRENT_DIR=`pwd`

case "$CURRENT_DIR" in
  *String1*) echo "String1 present" ;;
  *String2*) echo "String2 present" ;;
  *)         echo "else" ;;
esac

ksh 또는 bash와 같은 확장 쉘에는 멋진 일치 메커니즘이 있지만 이전 스타일 case은 놀랍도록 강력합니다.


40

슬프게도, 나는 이것을 sh에서 수행하는 방법을 모른다. 그러나 bash를 사용하면 (버전 3.0.0부터 시작) 아마도 다음과 같이 = ~ 연산자를 사용할 수 있습니다.

#!/bin/bash
CURRENT_DIR=`pwd`

if [[ "$CURRENT_DIR" =~ "String1" ]]
then
 echo "String1 present"
elif [[ "$CURRENT_DIR" =~ "String2" ]]
then
 echo "String2 present"
else
 echo "Else"
fi

추가 보너스 (및 / 또는 문자열에 재미있는 문자가있는 경우 경고)로 = ~는 인용 부호를 생략하면 정규 표현식을 올바른 피연산자로 받아들입니다.


3
정규 표현식을 인용하지 않으면 일반적으로 작동 하지 않습니다 . 예를 들어 [[ test =~ "test.*" ]]vs를 시도하십시오 [[ test =~ test.* ]].
l0b0

1
글쎄, 원래 질문에서와 같이 하위 문자열을 테스트하는 경우 제대로 작동하지만 올바른 피연산자를 정규식으로 취급하지는 않습니다. 더 명확하게 답변을 업데이트하겠습니다.
John Hyland

3
이것은 질문에 따라 POSIX sh가 아닌 Bash입니다.
리드

28
#!/usr/bin/env sh

# Searches a subset string in a string:
# 1st arg:reference string
# 2nd arg:subset string to be matched

if echo "$1" | grep -q "$2"
then
    echo "$2 is in $1"
else 
    echo "$2 is not in $1"
fi

2
변경 grep -q "$2"grep -q "$2" > /dev/null원치 않는 출력을 방지하기 위해.
Victor Sergienko

15

다음은 문제의 다양한 솔루션에 대한 링크 입니다.

가장 인간이 읽을 수있는 의미로 사용하는 것이 가장 좋습니다.

스타 와일드 카드 방법

if [[ "$string" == *"$substring"* ]]; then
    return 1
fi
return 0

sh나는이에 "알 수없는 피연산자"을 받았다. Bash와 함께 작동합니다.
절반

13
[[POSIX가 아닙니다
Ian

14
case $(pwd) in
  *path) echo "ends with path";;
  path*) echo "starts with path";;
  *path*) echo "contains path";;
  *) echo "this is the default";;
esac


2
test $(echo "stringcontain" "ingcon" |awk '{ print index($1, $2) }') -gt 0 && echo "String 1 contain string 2"

-> 출력 : 문자열 1은 문자열 2를 포함합니다.


2

'test'프로그램에 대한 맨 페이지를 참조하십시오. 디렉토리의 존재를 테스트하는 경우 일반적으로 다음과 같은 작업을 수행합니다.

if test -d "String1"; then
  echo "String1 present"
end

실제로 문자열을 일치 시키려면 bash 확장 규칙 및 와일드 카드를 사용할 수 있습니다.

if test -d "String*"; then
  echo "A directory starting with 'String' is present"
end

좀 더 복잡한 작업을 수행해야하는 경우 expr과 같은 다른 프로그램을 사용해야합니다.


1
두 번째 예에는 가짜 큰 따옴표 ( ")가있는 것 같습니다.
Alexis Wilke

2

긴 텍스트에 단어가 포함되어 있는지 확인하려는 특수한 경우에는 긴 텍스트를 반복하여 반복 할 수 있습니다.

found=F
query_word=this
long_string="many many words in this text"
for w in $long_string; do
    if [ "$w" = "$query_word" ]; then
          found=T
          break
    fi
done

이것은 순수한 Bourne 쉘입니다.


1

"test"만큼 빠른 ksh 전용 방법을 원하면 다음과 같이 할 수 있습니다.

contains() # haystack needle
{
    haystack=${1/$2/}
    if [ ${#haystack} -ne ${#1} ] ; then
        return 1
    fi
    return 0
}

건초 더미에서 바늘을 삭제 한 다음 이전 건초 더미와 새로운 건초 더미의 문자열 길이를 비교하여 작동합니다.


1
결과를 반환 할 수 test없습니까? 에서처럼 return [ ${#haystack} -eq ${#1} ]?
Alexis Wilke

네 맞습니다. 평신도에게는 이해하기 쉽도록 이것을 그대로 두겠습니다. 코드에서 사용하는 경우 @AlexisWilke 메서드를 사용하십시오.
JoeOfTex 2016 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.