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
내가 여기서 뭘 잘못하고 있니?
답변
주요 문제는 이러한 유형의 테스트를 지원하지 않는 [[ ... ]]
스크립트에서 패턴 일치를 사용하고 있다는 것 /bin/sh
입니다. sh 파일에서 실행할 때 쉘 스크립트가 찾을 수 없음 오류를 발생 시키는 질문을 참조하십시오 . 그러나 수동으로 입력하면 명령이 작동합니다.
다른 문제는의 출력 ls
을 공백, 탭 및 줄 바꿈의 단어로 분할하기 전에 단일 문자열로 결합 하고 생성 된 단어에 파일 이름 globbing을 적용한다는 것입니다. 그런 다음이 결과를 반복합니다.
대신 :
#!/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
. a
캐릭터 테스트 는 case ... esac
. *a*
패턴은 일치하는 a
경우 아무 변화가없는 한, 존재하는 경우 파일 이름에 문자를. printf
문이 더있을 경우 실행되지됩니다 "기본 경우"에 a
문자열에.
와 시험 -e
과는 -L
확실히 우리가 루프 패턴이 아무것도 일치하지 않는 가장자리 케이스를 잡는 것을 위해 존재한다. 이 경우 패턴은 확장되지 않은 상태로 유지되므로 확장되지 않은 패턴과 실제 기존 파일을 구분할 수 있는지 확인하기 위해 -e
. -L
테스트는 루프 패턴과 동일한 이름을 가진 심볼 링크의 더 엣지 케이스를 잡으려고하지만, 그 어디 유효를 가리 키지 않습니다. bash
가 사용하기 때문에 아래 코드는이를 필요로하지 않는 nullglob
대신 (사용할 수있는 쉘 옵션 /bin/sh
).
출력이 *b*
아닌 패턴 확장에 대해 루프를 실행하면 ls
공백, 탭, 줄 바꿈 및 파일 이름 globbing 문자를 포함하는 파일 이름도 처리 할 수 있다는 이점이 있습니다 (파일 이름은 절대로 단일 문자열에 넣지 않습니다. 반복).
에서 bash
쉘, 당신은과 동일한 기능을 수행 할 수있는 [[ ... ]]
당신이 자신을하려고 노력처럼, 패턴 매칭 테스트 :
#!/bin/bash
cd Folder || exit 1
shopt -s nullglob
for name in *b*; do
[[ $name != *a* ]] && printf '%s\n' "$name"
done
또한보십시오:
- 셸 스크립트가 공백이나 기타 특수 문자로 인해 질식하는 이유는 무엇입니까?
- 큰 따옴표는 언제 필요합니까?
- 'ls'를 구문 분석하지 않는 이유는 무엇입니까 (대신 수행 할 작업)?
- printf가 에코보다 나은 이유는 무엇입니까?
Folder
포함 b
및 포함 하지 않는 파일 이름을 인쇄하려면 a
in zsh
및 해당 ~
( / 및 -not 제외 ) glob 연산자 :
#! /bin/zsh -
set -o extendedglob
print -rC1 -- Folder/(*b*~*a*)(N:t)
( 일치하는 파일이없는 곳에 오류를보고 하려면 N
(for nullglob
,)을 제거하십시오 .
에서는 ksh93
그 도입 (쉘 [[...]]
표준의 일부가되는 (오퍼레이터 sh
구) 및 &
( 및 ) 및 !(...)
( 하지 ) 연산자 :
#! /bin/ksh93 -
(
CDPATH= cd Folder &&
set -- ~(N)@(*b*&!(*a*)) &&
(($# > 0)) && printf '%s\n' "$@"
)
와 bash
(같은 쉘 zsh
도 KSH의 복사했습니다 [[...]]
사용하여 연산자), extglob
ksh88 글로브 사업자를 지원하고 nullglob
zsh을의의 효과를 얻을 N
글로브 규정 또는 ksh93
의 ~(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
가장 좋습니다 . 도우미 기능을 사용할 수도 있습니다.case
sh
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