Bash는 파일 이름을 바꾸기 위해 sed 문을 오해합니다.

Bash는 파일 이름을 바꾸기 위해 sed 문을 오해합니다.

이런 식으로 이름이 지정된 일련의 파일 이름을 바꾸고 싶습니다

name (10).ext
name (11).ext
...

도착하다

name_10.ext
name_11.ext
...

이 줄의 역할은 다음과 같습니다.

$ for i in name\ \(* ; do echo "$i" | sed -e 's! (\([0-9]\{2\}\))!_\1!' ; done
name_10.ext
name_11.ext
...

하지만 이것은 그렇지 않습니다:

$ for i in name\ \(* ; do mv "$i" "$(echo "$i" | sed -e 's! (\([0-9]\{2\}\))!_\1!')" ; done
bash: !_\1!': event not found

왜? 이 상황을 피하는 방법은 무엇입니까?


사용

$ bash --version
GNU bash, versione 4.3.48(1)-release (x86_64-pc-linux-gnu)

우분투 18.04에서.


그리고 여기유제!!내부 작은따옴표를 고려하고 !내부 작은따옴표, 내부 큰따옴표와 비교하는 간단한 사례를 보여줍니다 . 주석에서 지적했듯이 Bash는 이 두 경우에 다르게 동작합니다. 이는 Bash 버전에 관한 것입니다 4.3.48(1). 문제는 더 이상 존재하지 않는 것 같습니다 4.4.12(1)(그러나 경우에 따라 Bash 버전을 알 수 없으므로 이 한 줄짜리 내용은 피하는 것이 좋습니다).

Kusalananda의 답변에서 제안한 대로 sed구분 기호를 !로 바꾸면 #,

$ for i in name\ \(* ; do mv "$i" "$(echo "$i" | sed -e 's# (\([0-9]\{2\}\))#_\1#')" ; done

이 문제는 전혀 발생하지 않습니다.

답변1

대화형 셸에서 사용하면 !기록 확장이 활성화될 수 있습니다(스크립트에서는 문제가 되지 않음).

해결책은 표현식 !외부에 다른 구분 기호를 사용하는 것입니다 sed.

또 다른 종류의 bash루프:

for name in "name ("*").ext"; do
    if [[ "$name" =~ (.*)" ("([^\)]+)").ext" ]]; then
        newname="${BASH_REMATCH[1]}_${BASH_REMATCH[2]}.ext"
        printf 'Would move %s to %s\n' "$name" "$newname"
        # mv -i "$name" "$newname"
    fi
done

답변2

Larry Wall의 rename명령( renameDebian의 패키지, prenameRedHat의 패키지)을 사용할 수 있습니다. 이 명령은 (더 간단한 IMHO) Perl 정규식 구문을 사용하고 루프 코드를 작성하지 않고 args 파일을 반복합니다.

rename 's/ \(\d+\)/_$1/' name\ *

답변3

정확한 범위를 알고 있으면 다음과 같이 파일 이름을 바꿀 수 있습니다.

for i in {10..99}; do mv "name ($i).ext" "name_$i.ext"; done

또는 POSIX 전문가가 되고 싶다면:

for i in `seq 10 99`; do mv "name ($i).ext" "name_$i.ext"; done

관련 정보