"제목"으로 시작하는 이름을 가진 파일이 몇 개 있습니다. ".txt"로 끝나며, 그 사이에 다른 콘텐츠가 있을 수도 있고 없을 수도 있습니다. 예를 들어: title.txt
, title.abc.txt
, title.123.txt
.
이제 모두 다른 폴더에 복사하고 싶습니다. 하나의 명령을 사용하여 cp
모든 파일을 복사하는 방법은 무엇입니까?
정규 표현식을 사용하면 다음과 같은 작업을 수행할 수 있습니다.
ls | egrep 'title(\..*)*\.txt' | xargs -I{} cp {} destination_folder/
하지만 너무 복잡합니다. egrep
및 의 도움이 필요합니다 xargs
. 쉘의 내장 함수 glob/wildcard를 사용하여 마법을 수행하는 쉬운 방법이 있습니까? 그것은 다음과 같습니다:
cp title[magic]txt destination_folder/
답변1
표준 셸 와일드카드에는 해당 항목이 없지만 일부 셸에는 몇 가지 확장이 있습니다.
다루기 힘든
zsh에서 이는 #
다음 옵션으로 활성화되는 연산자 입니다 extendedglob
.
set -o extendedglob # best in ~/.zshrc
cp -- *title(.*)#.txt* dest/
e
glob 한정자를 사용하여 glob과 함께 ERE 또는 PCRE를 사용할 수 있습니다 .
cp -- *(e['[[ REPLY =~ "title(\..*)*\.txt" ]]']) dest/
( set -o rematchpcre
ERE 대신 PCRE를 사용하거나 -pcre-match
대신 이후에 사용)=~
zmodload zsh/pcre
케시
ksh(모든 버전)에서는 x*
다음과 같습니다 *(x)
.
cp -- *title*(.*).txt* dest/
세게 때리다
bash는 다음 옵션으로 ksh 연산자를 지원합니다 extglob
.
shopt -s extglob
cp -- *title*(.*).txt* dest/
크쉬 93
ksh93
정규식은 해당 glob에서 사용할 수 있습니다.
cp -- *~(E:title(\..*)*\.txt)* dest/
( E
을 위한두번째정규 표현식은 여기에서 확장됩니다.)
또한 다음을 사용하여 ERE를 전역 모드로 변환할 수도 있습니다.
$ printf '%P\n' 'title(\..*)*\.txt'
*title*(\.*)\.txt*
(이 백슬래시는 여기서 중복되지만)
답변2
기본 와일드카드에서 특정 동일한 정규식을 일치시키는 유일한 방법은 다음과 같습니다.
cp title[.]txt title.*.txt destination_folder/
파일이 존재한다고 가정합니다(또는 nullglob을 설정하면 파일이 전혀 없으면 cp 오류가 생성됩니다).
또는:
$ ksh -c '
set -- ~(N)title[.]txt ~(N)title.*.txt
[ $# -ge 1 ] && cp "$@" dir/
'
또는:
$ bash -O nullglob -c '
set -- title[.]txt title.*.txt
[ $# -ge 1 ] && cp "$@" dir/
'
또는 다른 껍질에서도 비슷합니다.
왜
*
기술적으로 glob에는 정규식과 동일할 수 있는 항목이 없습니다.
주로 정규식만으로는 *
의미가 없기 때문입니다. 앞에 뭔가가 오면 의미가 있으며, 이는 이전 표시(무언가) 0
이상을 반복하는 것을 의미합니다.
정확히 동등한 것은 다음과 같습니다: regex는 .*
glob와 정확히 동일합니다 *
.
정규식과 유사한 표현 title(\..*)*\.txt
은 title.*.txt
.
시작과 끝
grep에 대해 작성해야 하는 정확한 정규식은 다음과 같다고 가정합니다.
^title(\..*)*\.txt$
귀하의 진술과 일치합니다"제목"으로 시작하세요.그리고".txt"로 끝남. 정규식에서는 시작은 으로 표현하고 ^
, 끝도 로 표현해야 합니다.$
기본적으로 시작과 끝은 glob에 포함됩니다.
가리키다
점은 정규식의 특수 문자이므로 이스케이프해야 합니다 \.
.
점은 전역적으로 특별하지 않으며 이스케이프할 필요가 없습니다.
선택적 문자
하지만 glob(기본)에서는 선택적 문자를 표현할 방법이 없습니다.
(c|d)?
정규식에서 A 는 "선택적 c 또는 d"를 의미하거나 간단히 말해서 문자 c
또는d
0번 또는 1번, 기본 glob에는 해당 항목이 없습니다. 이를 위해서는 다음을 사용해야합니다.확장하다와일드카드. 선택적 문자열의 구문은 다음과 같습니다.
?(c|d) # glob
그래서:
?(.*) # zero or once `?( )` a dot followed by anything (`*`).
의미: 선택적으로 점 뒤에 아무 것도(비어 있는 경우에도) 일치합니다.
전체 큰 그림은 다음과 같습니다.
title?(.*).txt # only in extended globbing.
확장된 와일드카드를 설정하는 방법은 셸마다 다르며 이식 가능하지 않습니다.
ksh : on by default, no need to set anything.
bash : shopt -s extglob
zsh : set -o extendedglob
휴대용 (거의)
기본 와일드카드에서 특정 동일한 정규식을 일치시키는 유일한 방법은 다음과 같습니다.
echo title[.]txt title.*.txt
빈 공
그러나 위의 모든 경기는 일부 경기가 글로벌 확장의 결과가 될 것이라고 가정합니다. glob이 일치하는 항목을 찾지 못하는 경우(예: 파일을 title[.]txt
찾을 수 없는 경우 title.txt
) nullglob 셸 옵션을 설정하여 glob을 삭제해야 합니다(명령줄에 그대로 두는 대신).
하지만 이것도 이식성이 없습니다.
- ksh: nullglob 옵션이 없습니다. 사용에만 적합
echo ~(N)title?(.*).txt
- 배쉬:
shopt -s nullglob
. - 지쉬:
set -o NULL_GLOB
또는set -G
또한 nullglob이 설정되어 있고 일치하는 패턴이 없으면 cp
cp가 이 명령줄을 "확인"하기 때문에 오류가 생성됩니다.
cp dir/
출처가 제공되지 않습니다.
글로벌 실패
FailGlob도 비슷한 문제를 일으킬 수 있습니다. 여러 패턴 중 하나라도 일치하지 않으면 전체 명령이 실패합니다.
cp title[.]txt title?(.*).txt dir/
두 모드 중 하나가 실패하면 두 모드 모두 실패합니다.
결정적인
일치하는 항목이 전혀 없고 cp에서 오류가 발생하지 않더라도 cp를 작동시키는 유일한 방법은 다음과 같습니다.
$ bash -O nullglob -c '
set -- title[.]txt title.*.txt
[ $# -ge 1 ] && cp "$@" dir/
'
$ ksh -c '
set -- ~(N)title[.]txt ~(N)title.*.txt
[ $# -ge 1 ] && cp "$@" dir/
'