가변 하위 폴더 이름을 사용하여 여러 하위 폴더의 파일을 복사하고 싶습니다.
예:
mkdir rootdir
mkdir rootdir/dir1
mkdir rootdir/dir2
mkdir rootdir/dir3
touch rootdir/dir1/foo.txt
touch rootdir/dir2/foo.txt
touch rootdir/dir3/foo.txt
알려진 하위 폴더 이름을 사용하면 각 파일을 개별적으로 복사할 수 있습니다.
cp rootdir/dir1/foo.txt rootdir/dir1/bar.txt
cp rootdir/dir2/foo.txt rootdir/dir2/bar.txt
cp rootdir/dir3/foo.txt rootdir/dir3/bar.txt
하지만 하위 폴더의 개수도 알 수 없고 하위 폴더 이름도 알 수 없기 때문에(파일명을 알고 있음) 더 이상 이렇게 할 수 없습니다.
이 파일들을 찾을 수 있어요...
ls ./**/foo.txt
find . -name foo.txt
...하지만 이 정보를 cp(또는 대체 도구)로 전송할 수 있는 구문을 찾지 못했습니다.
답변1
몇 가지 옵션이 있습니다:
find rootdir -type f -name foo.txt -execdir cp {} bar.txt \;
foo.txt
이 명령은 이나 그 아래에 있는 일반 파일을 검색하고 rootdir
, 파일이 발견되면 동일한 디렉터리 cp
에 이름으로 복사하는 데 사용됩니다 . bar.txt
이 -execdir
옵션은 비표준이지만 일반적으로 구현되며 파일이 있는 디렉터리에서 지정된 유틸리티를 실행합니다. {}
찾은 파일의 이름으로 대체됩니다 .
또는,
find rootdir -type f -name foo.txt -exec sh -c '
for pathname do
cp "$pathname" "${pathname%/*}/bar.txt"
done' sh {} +
이는 기본적으로 동일한 작업을 수행하지만 sh -c
발견된 파일 배치를 포함하는 짧은 인라인 스크립트를 호출합니다 foo.txt
. in 루프는 cp
이러한 각 파일을 발견된 파일과 동일한 디렉토리에 복사하지만 경로 이름의 파일 이름 부분은 bar.txt
.
**
귀하의 질문에서 언급했듯이 ( bash
셸을 가정하여) 사용하십시오 .
shopt -s globstar nullglob dotglob
for pathname in rootdir/**/foo.txt; do
cp "$pathname" "${pathname%/*}/bar.txt"
done
에서는 하위 디렉터리를 반복적으로 일치시키 도록 셸 옵션을 bash
설정하고 숨겨진 이름도 일치하도록 패턴을 활성화합니다. 쉘 옵션을 사용하면 일치하는 항목이 없으면 패턴이 확장되지 않은 채로 남아 있는 것이 아니라 완전히 사라지게 됩니다.globstar
**
dotglob
nullglob
다시 말하지만, 다음을 사용하면( zsh
일반 파일을 명시적으로 요청하고 dotglob
및와 동일한 와일드카드 처리 활성화):nullglob
bash
for pathname in rootdir/**/foo.txt(.ND); do
cp $pathname $pathname:h/bar.txt
done
여기서는 경로 이름의 파일 이름 부분을 제거하는 것과 같습니다 $pathname:h
(꼬리 부분이 아닌 "머리 부분만"에서와 같음).$pathname
:h
답변2
를 통해 자동 로딩 기능을 zsh
사용할 수도 있습니다 zmv
.
autoload -Uz zmv # best in ~/.zshrc
zmv -C '(**/)(foo.txt)(#q.)' '${1}bar.txt'
또는:
zmv -C '**/foo.txt(#q.)' '$f:h/bar.txt'
루프를 수동으로 작성하는 것보다 이것을 사용하면 zmv
되돌릴 수 없는 실수를 방지하는 몇 가지 안전 검사가 있다는 장점이 있습니다.