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. 먼저 어떤 일이 발생하는지 확인하려면 한 번 테스트 실행해야 합니다.

shell 옵션은 쉘을 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 와 같은 배치 파일 이름 바꾸기 도구나 다음의 Perl 기반 변형 중 하나를 사용하는 zmvmmv입니다 rename.

zsh << 'EOF'
autoload zmv
zmv 'log_(*).txt' '${1}_log.txt'
EOF

또는

prename 's/log_(.*)\.txt/${1}_log.txt/' log*.txt

관련 정보