bash 터미널을 사용하여 표현식을 캡처하는 방법은 무엇입니까?

bash 터미널을 사용하여 표현식을 캡처하는 방법은 무엇입니까?

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

관련 정보