왜

"제목"으로 시작하는 이름을 가진 파일이 몇 개 있습니다. ".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/

eglob 한정자를 사용하여 glob과 함께 ERE 또는 PCRE를 사용할 수 있습니다 .

cp -- *(e['[[ REPLY =~ "title(\..*)*\.txt" ]]']) dest/

( set -o rematchpcreERE 대신 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(\..*)*\.txttitle.*.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이 설정되어 있고 일치하는 패턴이 없으면 cpcp가 이 명령줄을 "확인"하기 때문에 오류가 생성됩니다.

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/
  '

관련 정보