결합된 유니코드 문자 검색 및 바꾸기

결합된 유니코드 문자 검색 및 바꾸기

ä디렉터리 이름과 파일 이름에 일부 "특수" 문자( , ö, ü) 가 포함된 Debian 시스템에 깊은 폴더 구조가 있습니다 . 그러나 이는 "ISO-8859-1"이 아니라 유니코드 결합 문자 형태입니다. 내가 아는 한, a 두 개의 점(분음 부호/움라우트)을 "별도의" 문자로 추가하는 것은 간단한 문제입니다.

find 및 sed를 사용하여 모든 파일과 폴더의 이름을 일괄적으로 변경해 보았습니다.

#!/bin/bash

# Files - normal characters
find . -depth -name "*[äöüÄÖÜ]*" -exec bash -c 'mv "$1" "$(echo $1 | sed -e "s/ä/ae/g; s/ö/oe/g; s/ü/ue/g; s/Ä/Ae/g; s/Ö/Oe/g; s/Ü/Ue/g")"' _ {} \;
# Files - Unicode combining characters
find . -depth -name "*[äöüÄÖÜ]*" -exec bash -c 'mv "$1" "$(echo $1 | sed -e "s/ä/ae/g; s/ö/oe/g; s/ü/ue/g; s/Ä/Ae/g; s/Ö/Oe/g; s/Ü/Ue/g")"' _ {} \;

# Directories - normal characters
find . -depth -type d -name "*[äöüÄÖÜ]*" -exec bash -c 'mv "$1" "$(echo $1 | sed -e "s/ä/ae/g; s/ö/oe/g; s/ü/ue/g; s/Ä/Ae/g; s/Ö/Oe/g; s/Ü/Ue/g")"' _ {} \;
# Directories - Unicode combining characters
find . -depth -type d -name "*[äöüÄÖÜ]*" -exec bash -c 'mv "$1" "$(echo $1 | sed -e "s/ä/ae/g; s/ö/oe/g; s/ü/ue/g; s/Ä/Ae/g; s/Ö/Oe/g; s/Ü/Ue/g")"' _ {} \;

그러나 인수의 매개변수가 ISO-8859-1 대신 유니코드로 결합된 경우 파일/폴더 이름에 find나타나는 모든 항목 도 선택된 것으로 보입니다. 예를 들어,aä-nameä

$ find . -name "*[ä]*"  //<-- one letter ä
./filename_one_letter_ä
$ find . -name "*[ä]*"  //<-- combining letter ä
./filename_with_just_a
./filename_one_letter_ä
./filename_with_combining_diaeresis_ä

따라서  sed파일 이름을 변경하지 않고 전달하므로  예를 들어 " "에서 " "로 mv이름을 바꾸도록 요청할 때 불평합니다 (즉, 소스와 대상이 동일함).BaustandBaustand

find를 사용하여 검색할 수 없는 경우 Linux 시스템의 파일/폴더 구조에서 유니코드 ä, ö, ü, Ä, 의 모든 조합을 검색하고 바꾸는 방법은 무엇입니까 Ö? Ü시도해 볼 수 있는 다른 방법이 있나요?

내 파일 및 디렉터리 이름의 예는 다음과 같습니다.

/Projekte/03-11_Törggel_Mammern/Baustand/03-11_Törggel-Baustand_190501_0009.jpg

이름을 다음으로 바꾸고 싶습니다.

/Projekte/03-11_Toerggel_Mammern/Baustand/03-11_Toerggel-Baustand_190501_0009.jpg

출력 echo $LANG은 입니다 en_US.UTF-8.

답변1

이 ATM을 재현(또는 테스트)할 수는 없지만...

글쎄, 당신은 [xyz]일치를 알고 있습니다.x 또는 y 또는 z. 내 생각에 당신이 (결합 문자를 사용하여) 말할 때 [äöü…]그것은 보고 있는 것 같아요

  • a
  • (결합하다) ¨
  • o
  • (결합하다) ¨
  • u
  • (결합하다) ¨

a따라서 이름에 , o, 가 포함된 파일을 찾습니다 .u 또는(조합)  ¨, 반드시 그런 것은 아니지만 , 또는  .

따라서 별도로 찾아보십시오.

find . -depth -name "*ä*" -exec bash -c 'mv "$1" "$(echo "$1" | sed -e "s/ä/ae/g")"' _ {} ';'
find . -depth -name "*ö*" -exec bash -c 'mv "$1" "$(echo "$1" | sed -e "s/ö/oe/g")"' _ {} ';'
find . -depth -name "*ü*" -exec bash -c 'mv "$1" "$(echo "$1" | sed -e "s/ü/ue/g")"' _ {} ';'
find . -depth -name "*Ä*" -exec bash -c 'mv "$1" "$(echo "$1" | sed -e "s/Ä/Ae/g")"' _ {} ';'
find . -depth -name "*Ö*" -exec bash -c 'mv "$1" "$(echo "$1" | sed -e "s/Ö/Oe/g")"' _ {} ';'
find . -depth -name "*Ü*" -exec bash -c 'mv "$1" "$(echo "$1" | sed -e "s/Ü/Ue/g")"' _ {} ';'

(대괄호 제외). 일부 파일 이름에서는 (따옴표 제외) 이 echo $1실패할 수 있습니다. ( ';'동등함 \;; 스타일상 백슬래시를 피하는 것을 선호합니다.)

아니면 당신이진짜진짜하나의 명령으로 모든 작업을 수행하려면 다음을 시도하십시오.

find . -depth "(" -name "*ä*" -o -name "*ö*" -o -name "*ü*"     \
               -o -name "*Ä*" -o -name "*Ö*" -o -name "*Ü*" ")" \
       -exec bash -c 'mv "$1" "$(printf "%s" "$1" | sed -e "s/ä/ae/g; s/ö/oe/g; s/ü/ue/g; s/Ä/Ae/g; s/Ö/Oe/g; s/Ü/Ue/g")"' _ {} ';'

( printf "%s"기능적으로는 과 매우 유사 echo하지만 더 안전합니다. 스타일적으로는 일반적으로 (작은 따옴표 포함)을 사용합니다 . 여기서는 작은 따옴표( ) 문자열 안에 printf '%s'있기 때문에 큰 따옴표를 사용합니다 .)'mv …'

가능한

… "(" -iname "*ä*" -o -iname "*ö*" -o -iname "*ü*" ")" …

작동합니다.


LANG또한 처음에 시도한 작업을 로 설정하면 작동할 수도 있습니다 de_DE.UTF-8.

답변2

이것de-ASCII음역uconv당신이 원하는 것을 할 것 입니다. 예를 들어 사전 구성 및 분해된 문자와 대문자 및 소문자 버전은 다음과 같습니다 ä.

$ printf '\u00c4 \u00e4 A\u0308 a\u0308\n'
Ä ä Ä ä
$ printf '\u00c4\u00e4A\u0308a\u0308' | uconv -x name
\N{LATIN CAPITAL LETTER A WITH DIAERESIS}\N{LATIN SMALL LETTER A WITH DIAERESIS}\N{LATIN CAPITAL LETTER A}\N{COMBINING DIAERESIS}\N{LATIN SMALL LETTER A}\N{COMBINING DIAERESIS}
$ printf '\u00c4\u00e4A\u0308a\u0308 \u00c4 A\u0308 \u00c4B\n' | uconv -x de-ASCII
AeaeAeae AE AE AEB

(또한 상황에 따라 Ä"또는"으로 변경되는 점 에 유의하세요).AEAe

따라서 여기에서 다음과 같은 것을 사용하여 이름에 ASCII가 아닌 문자가 포함된 모든 파일을 변환해 볼 수 있습니다(zsh에서).

autoload zmv
zmv -n $'(**/)(*[^\1-\177]*)' '$1$(print -rn -- $2 | uconv -x de-ASCII)'

예:

$ touch $'\u00c4\u00e4A\u0308a\u0308'
$ touch $'St\ue9phane' $'Ste\u301phane'
$ zmv -n $'(**/)(*[^\1-\177]*)' '$1$(print -rn -- $2 | uconv -x de-ASCII)'
mv -- ÄäÄä AeaeAeae
mv -- Stéphane Stephane
mv -- Stéphane Stephane

만족스러우면 삭제 -n(테스트 실행)합니다.

또는 uconv이름을 바꿔야 하는 파일이 수백만 개 있는 경우를 대비하여 파일당 하나씩 실행하지 마세요.

files=(**/*[^$'\1-\177']*)
typeset -U basenames=($files:t)
typeset -A translation
print -rNC1 -- $basenames | uconv -x de-ASCII |
  for name in $basenames; do
    IFS= read -rd '' translated && translation[$name]=$translated
  done

zmv -n $'(**/)(*[^\1-\177]*)' '$1${translation[$2]-$2}'

분해된 형태의 분음 문자가 포함된 파일을 찾는 방법에 대한 보다 일반적인 질문에 대한 대답으로 결합된 분음 문자(U+308)만 찾으면 됩니다.

그래서:

find . -name $'*\u0308*'

또는 AOUaou 중 하나만 따라야 하는 경우:

find . -name $'*[AOUaou]\u0308*'

사전 결합된 형태의 경우 별도로 나열해야 합니다.

find . -name '*[ÄËÏÖÜäëïöüÿŸǕǖǗǘǙǚǛǜǞǟȪȫ΅ΐΪΫΰϊϋϔӒӓӚӛӜӝӞӟӤӥӦӧӪӫӬӭӰӱӴӵӸӹḦḧḮḯṎṏṲṳṺṻẄẅẌẍẗ⍡⍢⍣⍤⍥⍨⍩⸚]*'

또는:

find . -name $'*[\uA8\uC4\uCB\uCF\uD6\uDC\uE4\uEB\uEF\uF6\uFC\uFF\u178\u1D5\u1D6\u1D7\u1D8\u1D9\u1DA\u1DB\u1DC\u1DE\u1DF\u22A\u22B\u385\u390\u3AA\u3AB\u3B0\u3CA\u3CB\u3D4\u4D2\u4D3\u4DA\u4DB\u4DC\u4DD\u4DE\u4DF\u4E4\u4E5\u4E6\u4E7\u4EA\u4EB\u4EC\u4ED\u4F0\u4F1\u4F4\u4F5\u4F8\u4F9\u1E26\u1E27\u1E2E\u1E2F\u1E4E\u1E4F\u1E72\u1E73\u1E7A\u1E7B\u1E84\u1E85\u1E8C\u1E8D\u1E97\u2361\u2362\u2363\u2364\u2365\u2368\u2369\u2E1A]*'

$'\uXXXX'bash를 포함한 일부 다른 쉘은 이제 zsh를 사용한 표기법을 지원합니다.

관련 정보