여러 디렉터리(해당 이름이 목록에 나타나는 경우)의 파일을 단일 디렉터리로 복사합니다.

여러 디렉터리(해당 이름이 목록에 나타나는 경우)의 파일을 단일 디렉터리로 복사합니다.

나는 거대한 폴더 트리를 가지고 있으며, 각 폴더에는 약 3레벨 아래의 여러 하위 디렉터리가 있습니다. 다음은 레벨이 하나만 있는 예입니다.

$ tree
.
|-- AB.txt
|-- CD.txt
|-- destination_folder
|-- spreadsheet.txt
`-- subdirectory
    `-- EF.txt

2 directories, 4 files

다음과 같은 관심 있는 파일 이름 목록이 있습니다 spreadsheet.txt.

$ cat spreadsheet.txt 
AB.txt
CD.txt
EF.txt

spreadsheet.txt폴더에 나타나는 모든 파일을 복사하고 싶습니다 destination_folder. 도움을 주셔서 감사합니다! 나는 이것이 관련될 것이라고 생각했지만 find그것을 cp알아낼 수는 없는 것 같습니다.

답변1

find파일 이름에 개행 문자가 포함되어 있지 않다고 가정하고 파일 이름당 한 번 실행합니다 .

#!/bin/sh

mkdir -p destination_folder || exit 1
while IFS= read -r name; do
    find . -path ./destination_folder -prune -o \
        -type f -name "$name" -exec cp {} destination_folder \;
done <spreadsheet.txt

먼저 현재 디렉터리 내에 대상 디렉터리를 생성합니다(또는 실패 시 종료됩니다). 그런 다음 입력 파일을 한 줄씩 읽고 호출하여 find해당 이름을 가진 일반 파일을 찾습니다. 검색에서 대상 디렉토리를 발견할 때마다 다음을 find사용하여 명시적으로 이를 피합니다.-prune

올바른 이름의 파일을 찾으면 해당 파일이 대상 디렉터리에 복사됩니다. 여러 파일의 이름이 같은 경우 복사본을 destination_folder덮어씁니다.

현재 디렉터리가 크거나 파일 이름 목록이 길면(그러나 수천 줄은 아님) 작업 속도가 느려집니다. 그래서 우리는하나의우리에게 전화하세요 find. 아래 코드는 bash배열을 사용하므로 예를 들어 실행된다고 가정합니다 .

#!/bin/bash

mkdir -p destination_folder || exit 1

names=()
while IFS= read -r name; do
    names+=( -o -name "$name" )
done <spreadsheet.txt

find . -path ./destination_folder -prune -o \
    \( "${names[@]:1}" \) -type f -exec cp -t destination_folder {} +

여기서는 발견된 파일당 한 번이 아닌 가능한 한 적은 수의 호출을 수행하기 위해 cp -t(GNU cp확장)을 사용하기로 결정했습니다 .cp

위의 코드는 names최종적으로 find. 귀하의 질문에 나온 예에 따르면 위 코드 끝에서 실행되는 실제 명령은 다음과 같습니다.

find . -path ./destination_folder -prune -o '(' -name AB.txt -o -name CD.txt -o -name EF.txt ')' -type f -exec cp -t destination_folder '{}' +

대상 디렉토리에서 파일 이름 충돌 문제를 방지하려면 GNU 를 사용하는 경우(예: Linux 시스템에서) 또는 옵션을 cp사용하십시오 .cp-b--backup

Linux가 아닌 시스템에서는 일반적으로 cp패키지 관리자를 통해 GNU coreutils를 설치한 후 GNU를 사용할 수 있습니다.gcp


마지막 스크립트 /bin/sh(무제한 배열):

#!/bin/sh

mkdir -p destination_folder || exit 1

set --
while IFS= read -r name; do
    set -- -o -name "$name" "$@"
done <spreadsheet.txt

shift

find . -path ./destination_folder -prune -o \
    \( "$@" \) -type f -exec cp -t destination_folder {} +

답변2

간단한 for 루프:

for filename in $(cat spreadsheet.txt)
do
find . -name "$filename" -exec cp {} /destination/folder \;
done

관련 정보