log_<date>.txt
중첩된 디렉토리에 흩어져 있는 동일한 명명법을 공유하는 파일이 있습니다 root
. <date>
파일이 YYYYmmddHHMM 형식으로 생성된 날짜는 어디에 있습니까? 코드 호환성 문제로 인해 모든 파일의 이름을 다음으로 바꾸고 싶습니다.<date>_log.txt
표현식 을 캡처해야 한다는 것을 알고 있지만 <date>
Bash에서는 어떻게 수행합니까? 또한 중첩된 디렉터리에서 이 작업을 어떻게 수행합니까?
답변1
쉘 변수에 이러한 파일 중 하나의 이름이 있다고 가정하십시오 name
. log_
그런 다음 완료를 사용하여 변수 값에서 해당 비트를 제거 ${name#log_}
하고 .txt
완료를 사용하여 비트를 제거합니다 ${name%.txt}
. 남은 것은 날짜이며 그 형식은 본질적으로 흥미롭지 않습니다. 제거된 값을 가져와 _log_.txt
끝에 추가하여 새 이름을 만드는 것은 쉽습니다.
단일 디렉터리에 있는 파일에 대해 이 작업을 수행하려면 루프를 사용하세요. 이제 변수 값의 시작 부분에 있는 디렉터리 이름도 제거해야 합니다.
shopt -s nullglob
for name in root/log_*.txt; do
newname=root/${name#root/log_} # remove prefix, add root/ back
newname=${newname%.txt}_log.txt # remove suffix, add _log.txt back
printf 'Would move "%s" to "%s"\n' "$name" "$newname"
# mv -i "$name" "$newname"
done
mv
안전을 위해 실제 명령을 주석 처리했습니다. 먼저 어떤 일이 발생하는지 확인하려면 한 번 테스트 실행해야 합니다.
쉘 옵션은 쉘을 nullglob
만듭니다 .bash
제거하다확장되지 않은 채로 두는 대신 일치하지 않는 패턴. 이는 log_*.txt
주어진 디렉토리에 파일이 없으면 루프가 전혀 실행되지 않음을 의미합니다.
이는 현재 디렉토리를 포함한 모든 파일에 재귀적으로 적용될 수 있습니다.다소간루프의 패턴을 수정하세요.
shopt -s globstar nullglob
for name in ./**/log_*.txt; do
dirpath=${name%/*} # get path of directory
newname=$dirpath/${name#$dirpath/log_} # remove prefix, add directory path back
newname=${newname%.txt}_log.txt # remove suffix, add _log.txt back
printf 'Would move "%s" to "%s"\n' "$name" "$newname"
# mv -i "$name" "$newname"
done
다른 변경 사항에는 하위 디렉터리를 일치시킬 globstar
수 있는 셸 옵션 활성화가 포함됩니다 **
. 또한 새 이름 앞에 추가할 수 있도록 디렉터리 경로를 선택했습니다.
find
루프에 대한 입력을 생성하는 데 사용할 수도 있습니다 .
find . -type f -name 'log_*.txt' -exec sh -c '
for name do
dirpath=${name%/*} # get path of directory
newname=$dirpath/${name#$dirpath/log_} # remove prefix, add directory path back
newname=${newname%.txt}_log.txt # remove suffix, add _log.txt back
printf "Would move \"%s\" to \"%s\"\n" "$name" "$newname"
# mv -i "$name" "$newname"
done' sh {} +
이는 현재 디렉토리 또는 다음 디렉토리에서 이름이 일치하는 모든 일반 파일을 찾은 다음 기본적으로 위의 두 번째 변형의 루프와 동일한 작업을 수행하는 log_*.txt
인라인 스크립트에 일괄 전달합니다 .sh -c
답변2
zsh
's zmv
또는 mmv
의 Perl 기반 변형 중 하나 와 같은 배치 파일 이름 바꾸기 도구를 사용하는 것이 더 좋습니다 rename
.
zsh << 'EOF'
autoload zmv
zmv 'log_(*).txt' '${1}_log.txt'
EOF
또는
prename 's/log_(.*)\.txt/${1}_log.txt/' log*.txt