시험:
find . -mindepth 2 -type f -name '*.pdf' -exec bash -c 'f=${1#./}; mv "$1" "./${f//\//_}"' None {} \;
이것은 모든 파일 이름, 심지어 이름에 개행 문자가있는 파일에도 안전합니다.
작동 원리
-mindepth 2
이것은 현재 디렉토리에 이미있는 파일을 처리하지 않도록 지시합니다.
-type f -name '*.pdf'
이렇게하면 pdf
확장자 가있는 일반 파일로 검색이 제한 됩니다.
-exec bash -c '...' None {} \;
파일 이름을 첫 번째 인수로 제공하는 따옴표 붙은 문자열에서 명령을 실행합니다 $1
.
우리의 목적을 위해 문자열 None
은 단순히 자리 표시 자입니다. $0
bash 규칙에 따라에 할당 된 것은 우리가 실행하는 명령의 이름입니다.
f=${1#./}; mv "$1" "./${f//\//_}"
이렇게하면 (a) ./
파일 이름에서 접두사 가 제거 되고 (b) 파일이 새 이름으로 원하는 위치로 이동합니다.
${1#./}
bash의 접두사 제거 예제입니다 . 처음부터 제거 된 스트 린 $1
을 반환합니다 ./
. ${f//\//_}
bash의 패턴 대체 예입니다 . 문자열 $f
이 모두 /
로 대체 된 문자열 을 반환합니다 _
. 이러한 기능에 대한 자세한 내용을 읽으려면의 섹션을 참조 man bash
라는 제목 매개 변수 확장을 .
보다 효율적인 버전
위의 버전은 발견 된 모든 파일에 대해 bash를 호출합니다. 또는 발견 된 여러 파일에 대해 bash를 한 번만 호출 할 수 있습니다. 이를 위해 명령을 for
루프로 묶습니다.
find . -mindepth 2 -type f -name '*.pdf' -exec bash -c 'for f in "$@"; do f=${f#./}; echo mv "$f" "./${f//\//_}"; done' None {} +
대체 문제
우리가 원하는 모든 파일이 두 번째 수준의 디렉토리에 있고 우리가 이동 된 파일을 대신하도록 반전 디렉토리 이름의 순서를 갖고 싶어한다고 가정 ./path1_pathA_fileI.pdf
, 우리가 끝을 ./pathA_path1_fileI.pdf
. 이 경우 :
for d1 in */; do d1=${d1%/}; for d2 in "$d1"/*/; do d2=${d2%/}; p="${d2#$d1/}_$d1"; for f in "./$d2"/*.pdf; do echo mv "$f" "./${p}_${f#./$d2/}"; done; done; done
또는 자신의 명령을 선호하는 사람들은 여러 줄로 퍼져 있습니다.
for d1 in */
do
d1=${d1%/}
for d2 in "$d1"/*/
do
d2=${d2%/}
p="${d2#$d1/}_$d1"
for f in "./$d2"/*.pdf
do
echo mv "$f" "./${p}_${f#./$d2/}"
done
done
done