이름에 'Music'이라는 단어가 포함 된 파일과 폴더를 제외한 디렉토리의 내용을 복사하려고한다고 가정 해 봅시다.
cp [exclude-matches] *Music* /target_directory
이를 수행하기 위해 [제외 일치] 대신 무엇을해야합니까?
이름에 'Music'이라는 단어가 포함 된 파일과 폴더를 제외한 디렉토리의 내용을 복사하려고한다고 가정 해 봅시다.
cp [exclude-matches] *Music* /target_directory
이를 수행하기 위해 [제외 일치] 대신 무엇을해야합니까?
답변:
배쉬에서 당신이 가능하게하여 그것을 할 수있는 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
f
제외하고로 시작하는 모든 것을 어떻게 일치시킬 foo
까요?
extglob
쉘 옵션은 당신에게 명령 줄에서 더 강력한 패턴 매칭을 제공합니다.
당신은에 그것을 설정 shopt -s extglob
하고 그것을 해제 shopt -u extglob
.
귀하의 예에서는 처음에 다음을 수행합니다.
$ shopt -s extglob
$ cp !(*Music*) /target_directory
전체 사용 가능한 내선는 종료 글로브의 빙 사업자 (발췌입니다 man bash
) :
shopt 내장을 사용하여 extglob 쉘 옵션을 사용하면 여러 확장 패턴 일치 연산자가 인식됩니다. 패턴 목록은 |으로 구분 된 하나 이상의 패턴 목록입니다. 복합 패턴은 다음 하위 패턴 중 하나 이상을 사용하여 형성 될 수 있습니다.
- ? (pattern-list)
주어진 패턴이 0 번 또는 1 번 일치합니다.- * (pattern-list)
0 개 이상의 주어진 패턴과 일치- + (pattern-list)
주어진 패턴 중 하나 이상을 찾습니다- @ (pattern-list)
주어진 패턴 중 하나와 일치- ! (pattern-list)
주어진 패턴 중 하나를 제외한 모든 것과 일치
당신이없는 현재 디렉토리에있는 모든 파일 목록을하고 싶어한다면, 예를 들어, .c
또는 .h
파일을, 당신은 할 것이다 :
$ ls -d !(*@(.c|.h))
물론 일반적인 쉘 글 로빙이 작동하므로 마지막 예제는 다음과 같이 쓸 수도 있습니다.
$ ls -d !(*.[ch])
.c
또는 .h
파일 중 하나 가 디렉토리 인 경우 @Koveras .
D
하지만 디렉토리에 포함될 수있는 서브 디렉토리의 컨텐츠는 나열 하지 않습니다 D
.
bash에는 없지만 (내가 아는) :
cp `ls | grep -v Music` /target_directory
나는 이것이 당신이 찾고있는 것이 아니라는 것을 알고 있지만, 당신의 모범을 해결할 것입니다.
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
-maxdepth 1
비 재귀 위해?
find
사소한 파일 이름을 찾으면 백틱에서 사용하면 불쾌한 방식으로 중단됩니다.
개인적으로 선호하는 것은 grep과 while 명령을 사용하는 것입니다. 이를 통해 강력하면서도 읽기 쉬운 스크립트를 작성하여 원하는대로 정확하게 작업 할 수 있습니다. 또한 에코 명령을 사용하면 실제 작업을 수행하기 전에 드라 이런을 수행 할 수 있습니다. 예를 들면 다음과 같습니다.
ls | grep -v "Music" | while read filename
do
echo $filename
done
복사 할 파일을 인쇄합니다. 리스트가 올 바르면 다음 단계는 단순히 echo 명령을 다음과 같이 copy 명령으로 바꾸는 것입니다.
ls | grep -v "Music" | while read filename
do
cp "$filename" /target_directory
done
bash
사용할 수 while IFS='' read -r filename
있지만 개행은 여전히 문제입니다. 일반적으로 ls
파일을 열거하는 데 사용하지 않는 것이 가장 좋습니다 . 같은 도구 find
가 훨씬 더 적합합니다.
for file in *; do case ${file} in (*Music*) ;; (*) cp "${file}" /target_directory ; echo ;; esac; done
내가 사용하지 않는 아직 여기에 보지 못한 트릭 extglob
, find
또는이 grep
두 개의 파일 세트로 목록 및 치료하는 것입니다 "DIFF" 그들을 사용하여 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)
잠재적으로 유용합니다.
comm -23 <(ls) exclude_these.list
이를위한 하나의 솔루션은 find로 찾을 수 있습니다.
$ mkdir foo bar
$ touch foo/a.txt foo/Music.txt
$ find foo -type f ! -name '*Music*' -exec cp {} bar \;
$ ls bar
a.txt
찾기에는 몇 가지 옵션이 있으며 포함 및 제외에 대해 구체적으로 지정할 수 있습니다.
편집 : Adam은 의견에서 이것이 재귀 적이라고 언급했습니다. find 옵션 mindepth 및 maxdepth가이를 제어하는 데 유용 할 수 있습니다.
find -maxdepth 1 -not -name '*Music*'
/ target_directory
다음 작품은 *.txt
숫자로 시작하는 파일을 제외하고 현재 디렉토리의 모든 파일을 나열합니다 .
이 작품 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
두 번째 줄에서 case 문은 원하지 않는 파일을 제거하는 데 사용됩니다. –이 ${FILE##*/}
표현식은 파일 이름 (여기 /some/dir/
) 에서 선행 dir 이름 구성 요소를 제거하여 패턴이 파일의 기본 이름과 만 일치되도록합니다. (접미사를 기준으로 파일 이름 만 제거하는 경우 $FILE
대신 단축 할 수 있습니다 .)
세 번째 줄에서는 case
pattern [0-9]*
) 줄과 일치하는 모든 파일을 건너 뜁니다 ( continue
명령문은 for
루프 의 다음 반복 으로 건너 뜁니다 ). –을 사용하여 문자 (a–z)로 시작하지 않는 모든 파일을 건너 뛰는 것과 같이 여기에서 더 흥미로운 것을 수행 [!a-z]*
하거나 여러 패턴을 사용하여 여러 종류의 파일 이름 [0-9]*|*.bak
을 건너 뛸 수 있습니다 ( 예 : 두 .bak
파일 모두 파일 을 건너 뛰는 경우) 및 숫자로 시작하지 않는 파일.
*.txt
단지 대신 일치했습니다 *
). 지금 수정했습니다.
ls /dir/*/!(base*)