스크립트는 다음과 같습니다.
rm -v !\(*.yaml\) ;\
이것은 생산할 것입니다
rm: cannot remove '!(*.yaml)': No such file or directory
하지만 명령줄에서는 잘 작동합니다. 탈출을 위해 다양한 방법을 시도했습니다.
'\!\(\*.yaml\)'
`\!\(\*.yaml\)`
`!\(*.yaml\"\)`
"\!\(\*.yaml\)"
적절한 이스케이프 시퀀스를 알아낼 수 없는 것 같습니다. 이해가 되지 않습니다. 괄호를 제거하는 것이 나의 첫 번째 단계였습니다. 그리고 탈출을 시도했고 !
, 그 다음에는 *
. 또한 백틱 이스케이프 해제를 사용해 보았지만 "rm 누락된 피연산자" 오류가 발생했습니다. 나는 조금 어리둥절하다. 이미 약 한 시간을 소비했습니다. "yaml 대신 모든 것을 rm"하면 됩니다... 누구든지 버그를 발견하거나 수정 사항을 제안할 수 있습니까?
나는 또한 #!/bin/sh 및 #!/bin/bash를 시도했습니다. 조금이라도 효과가 있지 않을까 싶었습니다.
답변1
!(x)
Korn 쉘 글로벌 연산자입니다. 이 연산자를 포함하지만 1 이후에만 지원되는 glob 연산자 bash
의 하위 집합입니다 .ksh
shopt -s extglob
그래서:
shopt -s extglob
rm -f -- !(*.yaml)
이름이 .로 끝나는 파일을 제외하고 현재 디렉터리에서 숨겨지지 않은 모든 파일이 삭제됩니다 .yaml
.
아무튼 글로벌 오퍼레이터는아니요인용할 때 그렇게 인식되므로 \
(Bourne 쉘의 인용 연산자 중 하나)를 사용하는 것은 도움이 되지 않습니다.
쉘에서 이에 상응하는 것은 다음과 같습니다 zsh
:
rm -f -- ^*.yaml
이를 위해서는 set -o extendedglob
.
(또는 !(x)
이후에도 지원됩니다).emulate ksh
set -o kshglob
sh
확장 기능으로 지원을 sh
기반으로 하는 구현과 같은 일부 구현을 찾을 수 있지만 언어에는 동등한 구현이 없습니다.ksh
!(x)
¹ 이는 쉘 구문 분석에 영향을 미치므로 shopt
명령이 실행되어야 합니다.앞으로이러한 ksh 스프레드 연산자 중 하나를 포함하는 행은 다음과 같습니다.읽다그리고 구문 분석합니다. 예를 들어 에서는 bash -c 'shopt -s extglob; echo !(x)'
전체 행이 먼저 구문 분석된 후(extglob이 아직 열려 있지 않음) shopt
실행(음, 구문 오류가 없었다면 실행되었을 것임)되기 때문에 구문 오류가 발생합니다. bash -O extglob -c 'echo !(x)'
매우 좋은.
답변2
GLOBIGNORE
Bash에는 glob에서 제거할 파일 이름을 쉘에 알려주고 나머지 파일 이름(이 경우 rm -v
) 을 계속 사용 하는 변수라는 기능이 있습니다 .
다음은 데모입니다:
mkdir /tmp/this-test
cd /tmp/this-test
touch one.yaml two.yaml three.json four.txt
echo *
생산:
four.txt one.yaml three.json two.yaml
이제 GLOBIGNORE
.yaml 파일 무시를 설정한 다음 해당 효과를 비활성화합니다.
GLOBIGNORE='*.yaml'
echo *
GLOBIGNORE=
echo *
생산:
four.txt three.json
four.txt one.yaml three.json two.yaml
이 명령은 이름이 로 끝나지 않는 디렉토리를 삭제 rm -v *
합니다 .echo *
.yaml
GLOBIGNORE
:
각각 콜론( )으로 구분된 glob 표현식 목록이 있을 수 있습니다 . 예를 들어 GLOBIGNORE='*.yaml:*.json'
위 데모에서 이 값을 설정하면 이 GLOBIGNORE
값은 glob 목록에서 .yaml 및 .json 파일 이름을 제거하므로 four.txt
해당 파일만 표시되거나 제거됩니다.
답변3
find와 rm을 결합하는 또 다른 방법...
5개의 파일이 포함된 폴더로 시작
cd /path/to/files/
touch one.yaml two.yaml three.txt four.yaml five.json
이름 패턴을 제외할 수 있는 find 유틸리티를 사용할 수 있지만, 비재귀적 검색에 find를 사용하려면 -minlength 및 -maxlength를 1로 설정해야 합니다.
find /path/to/files -mindepth 1 -maxdepth 1 -type f ! -name '*.yaml' -exec rm -v '{}' \;
removed '/path/to/files/three.txt'
removed '/path/to/files/five.json'
그런 다음 찾은 각 파일에 대해 개별적으로 rm -v를 사용할 수 있습니다. 파일 수가 많은 경우 각 파일에 대해 개별적으로 rm을 호출하므로 속도가 느려질 수 있습니다.
그러나 -delete를 사용하면 자세한 출력 없이 훨씬 빠르게 동일한 효과를 얻을 수도 있습니다.
find /path/to/files -mindepth 1 -maxdepth 1 -type f ! -name '*.yaml' -delete