Shell:문자열에 지정된 문자가 포함되어 있는지 확인

Shell:문자열에 지정된 문자가 포함되어 있는지 확인
#!/bin/sh

TMP=$(cd Folder && ls)

for name in $TMP; do

  if [[ "${name}" != *"a"* -a ${name} == *"b"* ]] ;then
   echo $name
  fi

done

"a"가 없지만 "b"가 있는 이름을 출력하려고 합니다. 내가 얻는 오류는 다음과 같습니다.

./aufg7.sh: 6: [[: not found
./aufg7.sh: 6: [[: not found
./aufg7.sh: 6: [[: not found
./aufg7.sh: 6: [[: not found
./aufg7.sh: 6: [[: not found
./aufg7.sh: 6: [[: not found

내가 여기서 뭘 잘못하고 있는 걸까?

답변1

인쇄하려면 Folder다음을 포함하고 포함하지 않습니다.bazsh~와는 별개로/설마) 전역 연산자:

#! /bin/zsh -
set -o extendedglob
print -rC1 -- Folder/(*b*~*a*)(N:t)

(제거하십시오 N( nullglob일치하는 파일이 없는 경우 오류를 보고하려면).

(표준 구문의 일부가 아닌) 이 연산자를 도입하는 쉘 ksh93과 그 ([[...]]sh&그리고) 그리고 !(...)(아니요) 운영자:

#! /bin/ksh93 -
(
  CDPATH= cd Folder &&
    set -- ~(N)@(*b*&!(*a*)) &&
    (($# > 0)) &&
    printf '%s\n' "$@"
)

ksh의 연산자 도 복제하는 bash쉘을 사용하여 ksh88 glob 연산자에 대한 지원을 사용하고 zsh의 glob 한정자 또는 glob 연산자와 일부 이중 부정 (zsh[[...]]extglobnullglobNksh93~(N)|또는) 성취하다그리고:

#! /bin/bash -
(
  shopt -s extglob nullglob
  cd ./Folder &&
    set -- !(!(*b*)|*a*) &&
    (($# > 0)) &&
    printf '%s\n' "$@"
)

표준 sh구문에서:

#! /bin/sh -
(
  CDPATH= cd Folder || exit
  set -- [*]b[*] *b*
  [ "$1/$2" = '[*]b[*]/*b*' ] && exit # detect the case where the pattern
                                      # expands to itself because there's
                                      # no match as there's no nullglob
                                      # equivalent in sh
  shift
  for i do
    case $i in
      (*a*) ;;
      (*) set -- "$@" "$i"
    esac
    shift
  done
  [ "$#" -gt 0 ] && printf '%s\n' "$@"
)

cd읽기 권한은 있지만 검색 권한이 없으면 사용된 솔루션이 작동하지 않으므로 주의하시기 바랍니다 .Folder

보다 일반적으로, 문자열에 다른 문자열이 포함되어 있는지 확인하는 방법에 대한 일반적인 질문에 대답하려면 에서 패턴 일치를 수행하는 구문을 사용하는 sh것이 더 좋습니다 . 도우미 기능을 사용할 수도 있습니다.casesh

contains()
  case "$1" in
    (*"$2"*) true;;
    (*) false;;
  esac

다음과 같이 사용하세요:

if contains foobar o; then
  echo foobar contains o
fi
if ! contains foobar z; then
  echo foobar does not contain o
fi
if
  contains "$file" b &&
    ! contains "$file" a
then
  printf '%s\n' "$file contains b and not a "
fi

답변2

[[ ... ]]주요 문제는 실행 중인 스크립트에서 /bin/sh이러한 유형의 테스트를 지원하지 않는 패턴 일치를 사용하고 있다는 것입니다. 제목이 붙은 질문도 참조하세요.sh 파일에서 실행할 때 쉘 스크립트를 찾을 수 없음 오류가 발생합니다. 하지만 수동으로 명령을 입력하면 작동합니다.

또 다른 문제는 출력을 ls단일 문자열로 결합한 다음 이를 공백, 탭 및 줄 바꿈의 단어로 분할하고 결과 단어에 파일 이름 글로빙을 적용한다는 것입니다. 그런 다음 이 결과를 반복합니다.

대신에:

#!/bin/sh

cd Folder || exit 1

for name in *b*; do
    [ -e "$name" ] || [ -L "$name" ] || continue
    case $name in (*a*) ;; (*) printf '%s\n' "$name"; esac
done

Folder그러면 해당 문자가 포함된 디렉터리의 모든 파일을 반복 하고 b그렇지 않은 파일을 인쇄 합니다 a. 패턴 은 파일 이름의 특정 문자 (있는 경우)와 일치하며, 이 경우 아무 일도 일어나지 않습니다. 이러한 문은 "기본 사례"에 있으며 문자열에 없으면 해당 문이 실행됩니다.acase ... esac*a*aprintfa

-e사용 및 테스트의 목적은 -L루프 패턴이 어떤 것과도 일치하지 않는 극단적인 경우를 포착하는 것입니다. 이 경우 패턴은 확장되지 않은 상태 로 유지되므로 확장되지 않은 패턴과 실제 파일을 구별할 수 있는지 확인하기 위해 -e. -L유효한 곳을 가리 키지 마십시오. 아래 코드는 셸 옵션을 bash사용하기 때문에 이것이 필요하지 않습니다 nullglob(참조 자료에서는 사용할 수 없음 /bin/sh).

*b*출력 이 아닌 패턴 확장에 대해 루프를 실행하면 ls공백, 탭, 줄 바꿈 및 파일 이름 와일드카드가 포함된 파일 이름도 처리할 수 있다는 이점이 있습니다(파일 이름은 우리가 시도한 것처럼 단일 문자열에 맞지 않습니다).

bash셸 에서는 패턴 일치 테스트를 사용하여 [[ ... ]]직접 수행하려는 것과 동일한 작업을 수행할 수 있습니다.

#!/bin/bash

cd Folder || exit 1

shopt -s nullglob

for name in *b*; do
    [[ $name != *a* ]] && printf '%s\n' "$name"
done

또한보십시오:

관련 정보