어떻게 사용할 수 있습니 반전 또는 부정적인 때 와일드카드는 패턴 매칭에서 unix/linux 니까?
-
03-07-2019 - |
문제
말 복사하려는 디렉토리 내용을 제외하고 파일 및 폴더가 이름에 포함된 단어는'음악'.
cp [exclude-matches] *Music* /target_directory
어떻게 가야하는 장소에서의[제외-일치]to accomplish this?
해결책
Bash에서는 활성화하여 수행 할 수 있습니다 extglob
이와 같은 옵션 (교체 ls
~와 함께 cp
물론 대상 디렉토리를 추가하십시오)
~/foobar> shopt extglob
extglob off
~/foobar> ls
abar afoo bbar bfoo
~/foobar> ls !(b*)
-bash: !: event not found
~/foobar> shopt -s extglob # Enables extglob
~/foobar> ls !(b*)
abar afoo
~/foobar> ls !(a*)
bbar bfoo
~/foobar> ls !(*foo)
abar bbar
나중에 extglob을 비활성화 할 수 있습니다
shopt -u extglob
다른 팁
그만큼 extglob
쉘 옵션은 명령 줄에서 더 강력한 패턴 매칭을 제공합니다.
당신은 그것을 켜십시오 shopt -s extglob
, 그리고 그것을 끄십시오 shopt -u extglob
.
예에서는 처음에 다음과 같습니다.
$ shopt -s extglob
$ cp !(*Music*) /target_directory
전체 사용 가능 내선끝났다 글로벌빙 사업자는 (발췌 man bash
):
Shopt 내장을 사용하여 ExtGlob Shell 옵션이 활성화되면 여러 확장 패턴 매칭 연산자가 인식됩니다. 다음 설명에서, Pat Tern-List는 | |로 분리 된 하나 이상의 패턴의 목록입니다. 복합 패턴은 하나 이상의 다음 하위 패턴을 사용하여 형성 될 수 있습니다.
- ? (패턴 목록)
주어진 패턴의 0 또는 한 번의 발생과 일치합니다- *(패턴 목록)
주어진 패턴의 0 이상 발생과 일치합니다- +(패턴 목록)
주어진 패턴의 하나 이상의 발생과 일치합니다- @(패턴 목록)
주어진 패턴 중 하나와 일치합니다- ! (패턴 목록)
주어진 패턴 중 하나를 제외한 모든 것이 일치합니다
예를 들어, 현재 디렉토리에 모든 파일을 나열하려는 경우 .c
또는 .h
파일, 당신은 할 것입니다 :
$ ls -d !(*@(.c|.h))
물론 일반 쉘 글로킹이 작동하므로 마지막 예제는 다음과 같이 쓸 수 있습니다.
$ ls -d !(*.[ch])
bash (내가 알고있는)가 아니라 :
cp `ls | grep -v Music` /target_directory
나는 이것이 당신이 찾고 있던 것이 아니라는 것을 알고 있지만, 그것은 당신의 예를 해결할 것입니다.
exec 명령을 사용하는 MEM 비용을 피하려면 Xargs로 더 잘할 수 있다고 생각합니다. 다음은 더 효율적인 대안이라고 생각합니다.
find foo -type f ! -name '*Music*' -exec cp {} bar \; # new proc for each exec
find . -maxdepth 1 -name '*Music*' -prune -o -print0 | xargs -0 -i cp {} dest/
Bash에서, 대안 shopt -s extglob
입니다 GLOBIGNORE
변하기 쉬운. 더 나은 것은 아니지만 기억하기가 더 쉽습니다.
원래 포스터가 원하는 예일 수 있습니다.
GLOBIGNORE="*techno*"; cp *Music* /only_good_music/
완료되면 unset GLOBIGNORE
할 수 rm *techno*
소스 디렉토리에서.
당신은 또한 매우 간단한 것을 사용할 수 있습니다 for
고리:
for f in `find . -not -name "*Music*"`
do
cp $f /target/dir
done
내 개인적인 취향은 grep 및 while 명령을 사용하는 것입니다. 이를 통해 강력하지만 읽을 수있는 스크립트를 작성하여 원하는 것을 정확하게 수행하게됩니다. 또한 Echo 명령을 사용하면 실제 작업을 수행하기 전에 드라이 런을 수행 할 수 있습니다. 예를 들어:
ls | grep -v "Music" | while read filename
do
echo $filename
done
복사 할 파일을 인쇄합니다. 목록이 올바른 경우 다음 단계는 Echo 명령을 다음과 같이 복사 명령으로 간단히 바꾸는 것입니다.
ls | grep -v "Music" | while read filename
do
cp "$filename" /target_directory
done
중 하나 이것에 대한 솔루션을 찾을 수 있습니다 찾을 수 있습니다.
$ mkdir foo bar
$ touch foo/a.txt foo/Music.txt
$ find foo -type f ! -name '*Music*' -exec cp {} bar \;
$ ls bar
a.txt
찾기가 매우 몇 가지 옵션이,당신이 얻을 수있는 아주 특정에서 무엇을 포함 및 제외합니다.
편집:아담에서 의견 주목하는 이는 재귀적입니다.옵션을 찾을 수 있 mindepth 및 maxdepth 에 유용할 수 있습니다했습니다.
트릭을 나는 보지 못했 여기에는 아직 사용하지 않는 extglob
, find
, 나 grep
가를 치료하는 두 개의 파일 목록을 세 "차이" 을 사용하여 그들을 comm
:
comm -23 <(ls) <(ls *Music*)
comm
이 바람직 diff
이 없기 때문에 추가 크.
이를 반환 모든 요소의 설정 1, ls
, 는 지 에서도 설정 2, ls *Music*
.이 모두 필요합 세트에 있을 정렬하기 위해 제대로 작동합니다.에 대한 문제가 없 ls
고 glob 확장,하지만 경우에 당신은 같은 것을 사용하는 find
, 해야 호출 sort
.
comm -23 <(find . | sort) <(find . | grep -i '.jpg' | sort)
잠재적으로 유용합니다.
다음 작품은 모두 나열됩니다 *.txt
숫자로 시작하는 파일을 제외하고는 현재 DIR의 파일입니다.
이것은 작동합니다 bash
, dash
, zsh
그리고 다른 모든 posix 호환 쉘.
for FILE in /some/dir/*.txt; do # for each *.txt file
case "${FILE##*/}" in # if file basename...
[0-9]*) continue ;; # starts with digit: skip
esac
## otherwise, do stuff with $FILE here
done
라인에서 패턴
/some/dir/*.txt
원인이 될 것입니다for
루프는 모든 파일을 반복합니다/some/dir
누구의 이름이 끝나고 끝납니다.txt
.두 줄에서는 사례 명세서가 사용되지 않은 파일을 제거하는 데 사용됩니다. -
${FILE##*/}
표정/some/dir/
) 따라서 Patters는 파일의베이스 이름에만 일치 할 수 있습니다. (접미사를 기반으로 파일 이름을 잡초화하는 경우$FILE
대신에.)3 행에서는 모든 파일이 일치합니다
case
무늬[0-9]*
) 라인이 건너 뜁니다 (continue
진술은 다음 반복으로 점프합니다for
고리). - 당신이 원하는 경우 여기서 더 흥미로운 일을 할 수 있습니다.[!a-z]*
, 또는 여러 패턴을 사용하여 여러 종류의 파일 이름을 건너 뛸 수 있습니다.[0-9]*|*.bak
둘 다 파일을 건너 뜁니다.bak
숫자로 시작하지 않는 파일 및 파일.
이것은 정확히 '음악'을 제외 할 것입니다.
cp -a ^'Music' /target
이것은 음악과 같은 것을 제외하고? * 또는 *? 음악
cp -a ^\*?'complete' /target
cp -a ^'complete'?\* /target