#!/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
다음을 포함하고 포함하지 않습니다.b
a
zsh
~
와는 별개로/설마) 전역 연산자:
#! /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
[[...]]
extglob
nullglob
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
답변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
. 패턴 은 파일 이름의 특정 문자 (있는 경우)와 일치하며, 이 경우 아무 일도 일어나지 않습니다. 이러한 문은 "기본 사례"에 있으며 문자열에 없으면 해당 문이 실행됩니다.a
case ... esac
*a*
a
printf
a
-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
또한보십시오: