파일을 여러(가변) 폴더에 복사

파일을 여러(가변) 폴더에 복사

가변 하위 폴더 이름을 사용하여 여러 하위 폴더의 파일을 복사하고 싶습니다.

예:

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**dotglobnullglob

다시 말하지만, 다음을 사용하면( zsh일반 파일을 명시적으로 요청하고 dotglob및와 동일한 와일드카드 처리 활성화):nullglobbash

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되돌릴 수 없는 실수를 방지하는 몇 가지 안전 검사가 있다는 장점이 있습니다.

관련 정보