중첩된 와일드카드를 사용하여 복사 및 이름 바꾸기

중첩된 와일드카드를 사용하여 복사 및 이름 바꾸기

다음과 같은 파일 구조가 있습니다.

raw:
    F1:
        file1.pdf
    F2:
        file2.pdf
    (...)
pdf:
    (...)

폴더당 항상 하나의 PDF 파일만 있으며 파일/폴더 이름은 임의로 지정할 수 있습니다.

raw디렉토리의 모든 pdf 파일을 pdf 디렉토리로 복사하고 해당 파일 이름을 루트 폴더 이름으로 바꾸고 싶습니다 . 위 예의 경우 결과는 다음과 같습니다.

raw:
    F1:
        file1.pdf
    F2:
        file2.pdf
    (...)
pdf:
    F1.pdf
    F2.pdf
    (...)

와일드카드 복사에 대해 읽었지만 파일을 복사하려면 두 개의 중첩된 와일드카드를 사용해야 하기 때문에 이는 문제가 있는 것 같습니다. 따라서 이것은 분명히 작동하지 않습니다.

cp raw/*/*.pdf pdf/*.pdf

이 문제를 해결할 수 있는 방법이 있습니까? 아니면 내 폴더를 반복하고 정규식을 사용하여 경로를 분할해야 합니까?

답변1

복사에 와일드카드를 사용할 수 있으며 괜찮습니다. 그러나 파일을 복사하는 것이 아니라 파일 이름을 바꿔야 합니다. 즉, 각 파일에 새 이름을 할당해야 하므로 루프가 불가피합니다. 기껏해야 루핑을 수행하는 도구를 사용할 수 있습니다.

perl-rename( renamedDebian 기반 시스템에서 호출) 있는 경우 다음을 수행할 수 있습니다.

$ rename -n 's|raw/([^/]+)/.*pdf|pdf/$1.pdf|' raw/*/*.pdf
raw/F1/file1.pdf -> pdf/F1.pdf
raw/F2/file2.pdf -> pdf/F2.pdf

.pdf이렇게 하면 이 작업을 수행하는 대신 로 끝나는 모든 파일 이름을 찾을 raw수 있습니다 .pdf. 따라서 만족스러우면 실제로 파일 이름을 바꾸지 않고 해당 명령을 실행하십시오.pdf/-n-n

rename 's|raw/([^/]+)/.*pdf|pdf/$1.pdf|' raw/*/*.pdf

또는 쉘 루프를 사용할 수 있습니다.

for f in raw/*/*pdf; do 
    new=$(sed -E 's|raw/([^/]+)/.*|pdf/\1.pdf|' <<<"$f"); 
    echo "mv -- $f $new"; 
done
mv raw/F1/file1.pdf pdf/F1.pdf
mv raw/F2/file2.pdf pdf/F2.pdf

다시 한 번, 작동하는 것에 만족하면 에코를 제거하여 실제로 파일 이름을 바꿉니다.

for f in raw/*/*pdf; do 
    new=$(sed -E 's|raw/([^/]+)/.*|pdf/\1.pdf|' <<<"$f"); 
    mv -- "$f" "$new"; 
done

중요한: 두 솔루션 모두 디렉터리당 파일이 하나만 있다고 가정하므로 충돌이 발생하지 않습니다. 동일한 하위 디렉터리에 있는 모든 파일은 동일한 이름을 갖기 때문에 추가 파일이 제거됩니다.

-i각 해당 도구의 옵션( mvan )을 사용해 보면 rename동일한 이름의 파일을 덮어쓰기 전에 확인 메시지를 표시하게 됩니다. 이렇게 하면 해결책이 만들어집니다.

rename -i 's|raw/([^/]+)/.*pdf|pdf/$1.pdf|' raw/*/*.pdf

그리고

for f in raw/*/*pdf; do 
    new=$(sed -E 's|raw/([^/]+)/.*|pdf/\1.pdf|' <<<"$f"); 
    mv -i -- "$f" "$new"; 
done

답변2

중첩 루프를 사용하십시오.

shopt -s nullglob  # To prevent failures if there's no pdf in a dir.
for dir in raw/* ; do
    for pdf in "$dir"/*.pdf ; do
        cp -- "$pdf" pdf/"${dir#raw/}".pdf  # Remove the "raw/" part
    done
done

또는 파일을 반복하고 매개변수 확장을 두 번 적용하여 대상 이름을 생성합니다.

for pdf in raw/*/*.pdf ; do
    target=${pdf#raw/}  # Remove the "raw/" part
    target=${target%/*}  # Remove the filename
    cp -- "$pdf" pdf/"$target".pdf
done

답변3

그리고 zsh:

autoload -Uz zmv # best in ~/.zshrc
zmv -C 'raw/(*)/*.pdf' 'pdf/$1.pdf'

관련 정보