Programing

bash에서 문자열이 어떤 값으로 시작하는지 어떻게 확인할 수 있습니까?

lottogame 2020. 10. 2. 21:23
반응형

bash에서 문자열이 어떤 값으로 시작하는지 어떻게 확인할 수 있습니까?


문자열이 "node"(예 : "node001")로 시작하는지 확인하고 싶습니다. 같은 것

if [ $HOST == user* ]  
  then  
  echo yes  
fi

어떻게하면 올바로 할 수 있습니까?


HOST가 "user1"인지 또는 "node"로 시작하는지 확인하기 위해 표현식을 결합해야합니다.

if [ [[ $HOST == user1 ]] -o [[ $HOST == node* ]] ];  
then  
echo yes 
fi

> > > -bash: [: too many arguments

올바르게하는 방법?


Advanced Bash Scripting Guide 의이 스 니펫 은 다음과 같이 말합니다.

# The == comparison operator behaves differently within a double-brackets
# test than within single brackets.

[[ $a == z* ]]   # True if $a starts with a "z" (wildcard matching).
[[ $a == "z*" ]] # True if $a is equal to z* (literal matching).

그래서 거의 정확했습니다. 단일 대괄호가 아니라 이중 대괄호가 필요했습니다 .


두 번째 질문과 관련하여 다음과 같이 작성할 수 있습니다.

HOST=user1
if  [[ $HOST == user1 ]] || [[ $HOST == node* ]] ;
then
    echo yes1
fi

HOST=node001
if [[ $HOST == user1 ]] || [[ $HOST == node* ]] ;
then
    echo yes2
fi

에코가

yes1
yes2

Bash의 if구문은 (IMO)에 익숙해지기 어렵습니다.


최근 bash (v3 +)를 사용하는 경우 bash 정규식 비교 연산자 =~, 즉

if [[ "$HOST" =~ ^user.* ]]; then
    echo "yes"
fi

this or that정규식에서 일치하려면 |, 즉

if [[ "$HOST" =~ ^user.*|^host1 ]]; then
    echo "yes"
fi

주-이것은 '적절한'정규식 구문입니다.

  • user*의 의미 use와 0 개 이상의 발생이 r있으므로 useuserrrr일치합니다.
  • user.*수단 user및 모든 문자의 제로 또는-이상의 발생, 그래서 user1, userX일치합니다.
  • ^user.*user.*$ HOST의 시작 부분에 있는 패턴과 일치 함을 의미합니다 .

정규 표현식 구문에 익숙하지 않은 경우이 리소스를 참조하세요 .

참고-각각의 새로운 질문을 새로운 질문으로 묻는 것이 더 낫습니다. 그러면 stackoverflow가 더 깔끔하고 유용 해집니다. 참조를 위해 언제든지 이전 질문으로 돌아가는 링크를 포함 할 수 있습니다.


스크립팅의 주요 포인트 중 하나가 이식성이기 때문에 항상 bash 확장을 사용하는 대신 POSIX sh를 고수하려고합니다. ( 프로그램 연결 외에도 대체하지 않음)

sh에서는 "is-prefix"조건을 확인하는 쉬운 방법이 있습니다.

case $HOST in node*)
    your code here
esac

얼마나 오래된 감안할 때, 비전 및 crufty 쉬입니다 (배쉬는 치료되지 않습니다 : 그것은 더 적은 일관성이 적은 휴대용, 복잡), 나는 아주 좋은 기능적인 측면을 지적하고 싶습니다 일부 구문 요소는 좋아하지만 case내장되어 있습니다 , 결과 구조는 다른 작업과 다르지 않습니다. 동일한 방식으로 구성 할 수 있습니다.

if case $HOST in node*) true;; *) false;; esac; then
    your code here
fi

또는 더 짧게

if case $HOST in node*) ;; *) false;; esac; then
    your code here
fi

또는 짧습니다 ( !언어 요소로 표시하기 위해-하지만 지금은 나쁜 스타일입니다)

if ! case $HOST in node*) false;; esac; then
    your code here
fi

명시 적이기를 좋아한다면 고유 한 언어 요소를 작성하십시오.

beginswith() { case $2 in "$1"*) true;; *) false;; esac; }

이것은 실제로 꽤 멋지지 않습니까?

if beginswith node "$HOST"; then
    your code here
fi

그리고 sh는 기본적으로 작업과 문자열 목록 (및 내부적으로 작업이 구성되는 프로세스) 일 뿐이므로 이제 가벼운 함수 프로그래밍을 수행 할 수도 있습니다.

beginswith() { case $2 in "$1"*) true;; *) false;; esac; }
checkresult() { if [ $? = 0 ]; then echo TRUE; else echo FALSE; fi; }

all() {
    test=$1; shift
    for i in "$@"; do
        $test "$i" || return
    done
}

all "beginswith x" x xy xyz ; checkresult  # prints TRUE
all "beginswith x" x xy abc ; checkresult  # prints FALSE

이것은 우아합니다. 내가 sh를 사용하여 진지하게 옹호하는 것은 아닙니다. 실제 요구 사항에서 너무 빨리 깨집니다 (람다가 없어서 문자열을 사용해야합니다.하지만 문자열로 함수 호출을 중첩하는 것은 불가능하며 파이프는 불가능합니다 ...)


확인하려는 문자열 부분 만 선택할 수 있습니다.

if [ ${HOST:0:4} = user ]

후속 질문의 경우 OR를 사용할 수 있습니다 .

if [[ $HOST == user1 || $HOST == node* ]]

이미 게시 된 다른 방법을 선호하지만 일부 사람들은 다음을 사용하고 싶어합니다.

case "$HOST" in 
    user1|node*) 
            echo "yes";;
        *)
            echo "no";;
esac

편집하다:

위의 사례 진술에 귀하의 대안을 추가했습니다.

편집 한 버전에는 대괄호가 너무 많습니다. 다음과 같아야합니다.

if [[ $HOST == user1 || $HOST == node* ]];

여기에서 대부분의 답변이 매우 정확하지만 대부분은 불필요한 바 시즘을 포함합니다. POSIX 매개 변수 확장 은 필요한 모든 것을 제공합니다.

[ "${host#user}" != "${host}" ]

[ "${host#node}" != "${host}" ]

${var#expr}일치하는 가장 작은 접두사를 expr제거 ${var}하고 반환합니다. 따라서 ( )로 시작 ${host}하지 않으면 ( )는 .usernode${host#user}${host#node}${host}

exprfnmatch()와일드 카드를 허용 하므로 ${host#node??}친구들도 작동합니다.


# bash에서 의미가 있기 때문에 다음 솔루션을 얻었습니다.
또한 공백 등을 극복하기 위해 문자열을 ""로 묶는 것이 좋습니다.

A="#sdfs"
if [[ "$A" == "#"* ]];then
    echo "skip comment line"
fi

@OP, 두 질문 모두 case / esac을 사용할 수 있습니다.

string="node001"
case "$string" in
  node*) echo "found";;
  * ) echo "no node";;
esac

두 번째 질문

case "$HOST" in
 node*) echo "ok";;
 user) echo "ok";;
esac

case "$HOST" in
 node*|user) echo "ok";;
esac

또는 배쉬 4.0

case "$HOST" in
 user) ;& 
 node*) echo "ok";; 
esac

Mark Rushakoff의 최고 순위 답변에 구문 세부 사항을 조금 더 추가했습니다.

표현식

$HOST == node*

다음과 같이 쓸 수도 있습니다.

$HOST == "node"*

The effect is the same. Just make sure the wildcard is outside the quoted text. If the wildcard is inside the quotes it will be interpreted literally (i.e. not as a wildcard).


if [ [[ $HOST == user1 ]] -o [[ $HOST == node* ]] ];  
then  
echo yes 
fi

doesn't work, because all of [, [[ and test recognize the same nonrecursive grammar. see section CONDITIONAL EXPRESSIONS in your bash man page.

As an aside, the SUSv3 says

The KornShell-derived conditional command (double bracket [[]]) was removed from the shell command language description in an early proposal. Objections were raised that the real problem is misuse of the test command ([), and putting it into the shell is the wrong way to fix the problem. Instead, proper documentation and a new shell reserved word (!) are sufficient.

Tests that require multiple test operations can be done at the shell level using individual invocations of the test command and shell logicals, rather than using the error-prone -o flag of test.

you'd need to write it this way, but test doesn't support it:

if [ $HOST == user1 -o $HOST == node* ];  
then  
echo yes 
fi

test uses = for string equality, more importantly it doesn't support pattern matching.

case / esac has good support for pattern matching:

case $HOST in
user1|node*) echo yes ;;
esac

it has the added benefit that it doesn't depend on bash, the syntax is portable. from the Single Unix Specification, The Shell Command Language:

case word in
    [(]pattern1) compound-list;;
    [[(]pattern[ | pattern] ... ) compound-list;;] ...
    [[(]pattern[ | pattern] ... ) compound-list]
esac

I tweaked @markrushakoff's answer to make it a callable function:

function yesNo {
  # prompts user with $1, returns true if response starts with y or Y or is empty string
  read -e -p "
$1 [Y/n] " YN

  [[ "$YN" == y* || "$YN" == Y* || "$YN" == "" ]]
}

Use it like this:

$ if yesNo "asfd"; then echo "true"; else echo "false"; fi

asfd [Y/n] y
true

$ if yesNo "asfd"; then echo "true"; else echo "false"; fi

asfd [Y/n] Y
true

$ if yesNo "asfd"; then echo "true"; else echo "false"; fi

asfd [Y/n] yes
true

$ if yesNo "asfd"; then echo "true"; else echo "false"; fi

asfd [Y/n]
true

$ if yesNo "asfd"; then echo "true"; else echo "false"; fi

asfd [Y/n] n
false

$ if yesNo "asfd"; then echo "true"; else echo "false"; fi

asfd [Y/n] ddddd
false

Here is a more complex version that provides for a specified default value:

function toLowerCase {
  echo "$1" | tr '[:upper:]' '[:lower:]'
}

function yesNo {
  # $1: user prompt
  # $2: default value (assumed to be Y if not specified)
  # Prompts user with $1, using default value of $2, returns true if response starts with y or Y or is empty string

  local DEFAULT=yes
  if [ "$2" ]; then local DEFAULT="$( toLowerCase "$2" )"; fi
  if [[ "$DEFAULT" == y* ]]; then
    local PROMPT="[Y/n]"
  else
    local PROMPT="[y/N]"
  fi
  read -e -p "
$1 $PROMPT " YN

  YN="$( toLowerCase "$YN" )"
  { [ "$YN" == "" ] && [[ "$PROMPT" = *Y* ]]; } || [[ "$YN" = y* ]]
}

Use it like this:

$ if yesNo "asfd" n; then echo "true"; else echo "false"; fi

asfd [y/N]
false

$ if yesNo "asfd" n; then echo "true"; else echo "false"; fi

asfd [y/N] y
true

$ if yesNo "asfd" y; then echo "true"; else echo "false"; fi

asfd [Y/n] n
false

grep

Forgetting performance, this is POSIX and looks nicer than case solutions:

mystr="abcd"
if printf '%s' "$mystr" | grep -Eq '^ab'; then
  echo matches
fi

Explanation:


Another thing you can do is cat out what you are echoing and pipe with inline cut -c 1-1

참고URL : https://stackoverflow.com/questions/2172352/in-bash-how-can-i-check-if-a-string-begins-with-some-value

반응형