[unix] 파일 이름에서 공백, 하이픈 및 밑줄을 삭제 하시겠습니까?

디렉토리의 모든 파일 또는 선택한 파일에서 공백, 하이픈 및 밑줄을 삭제하는 좋은 명령은 무엇입니까?

Thunar 사용자 지정 동작과 함께 다음 명령을 사용하여 파일 이름을 슬러그 화합니다.

for file in %N; do mv "$file" "$(echo "$file" | tr -s ' ' | tr ' A-Z' '-a-z' | tr -s '-' | tr -c '[:alnum:][:cntrl:].' '-')"; done

그러나이 명령은 공백을 대시 / 하이픈 및 소문자 대문자로만 바꿉니다.

터미널에서 다음 명령을 사용하여 폴더의 수천 개의 파일 이름에서 공백을 삭제했으며 매우 빠르게 작동했습니다.

 rename "s/ //g" *

다시 말하지만 공백 만 삭제하고 하이픈 / 대시 및 밑줄도 삭제하지 않습니다.

이상적으로는 파일 이름에 공백, 하이픈 / 대시 및 밑줄을 원하지 않습니다. 선택한 파일에서 Thunar 사용자 정의 작업과 함께 명령을 사용할 수 있다면 좋을 것입니다.



답변

패키지 rename와 함께 제공 되는 버전 perl은 정규식을 지원합니다.

rename "s/[-_ ]//g" *

또는

rename -i "s/[-_ ]//g" *

-i플래그가 편리해집니다 rename대신 자동으로 덮어 쓰기의 대상이 이미 존재하는 경우 프롬프트 대화 형 모드를 사용합니다.

Perl의 이름 변경은 때때로이라고 prename합니다.

펄의 이름 바꾸기와 유틸리티 리눅스의 이름 바꾸기

데비안과 유사한 시스템에서 perl의 이름 바꾸기가 기본값 인 것으로 보이며 위의 명령이 작동해야합니다.

일부 배포판에서는 renameutil-linux 의 유틸리티가 기본값입니다. 이 유틸리티는 Perl과 완전히 호환되지 않습니다 rename.

  • 먼저 : Perl ‘s rename가 name 아래에 있는지 확인하십시오 prename.

  • 데비안 : Perl의 이름 바꾸기가 기본값이어야합니다. 로도 제공됩니다 prename. 그러나 rename실행 파일은 제어하에 있으며 /etc/alternatives다른 것으로 변경되었을 수 있습니다.

  • archlinux : Run pacman -S perl-rename및 명령은로 사용할 수 있습니다 perl-rename. 보다 편리한 이름을 위해 별명을 작성하십시오. (모발 끝 : ChiseledAbs)

  • 맥 OSX가 에 따르면 이 답변 , rename사제를 통해 사용 OSX에 설치할 수 있습니다 :

    brew install rename 
  • 직접 다운로드 : rename Perl Monks에서도 제공됩니다.

     wget 'http://www.perlmonks.org/?displaytype=displaycode;node_id=303814' -O rename

답변

모든 tr명령을 sed대체 명령으로 바꿉니다. 예 :

for file in %N; do 
    mv "$file" "$(echo "$file" | sed 's/[ _-]//g')"
done


답변

계산하지 mv, 당신은 정말 전혀 이에 대한 외부 공정이 필요하지 않습니다 – 당신은 할 수 종류 단지의 그들.

ifsqz() ( LC_ALL=C sqz=$1
    isf() { [ -e "$1" ] || [ -L "$1" ] ; }  
    set -- * ; set -f
    for f do isf "$f" || break
    IFS=$sqz; set -- $f; IFS=
    isf "$*" || mv -- "$f" "$*"
    done
)

그럼에도 불구하고 mv파일 당 호출 을 의미 하므로 아마도 rename더 좋습니다. 이것은 단지 주어진 POSIX 작업을해야하지만 mv$PATH와 POSIX 쉘.

그래서 저는 이것에 대한 일종의 미친 데모를 생각해 냈습니다. 테스트 세트는 다음과 같이 생성됩니다.

tee - - - - <<CGEN |\
dd cbs=90 conv=unblock |\
sed 'G;$!N'";s/^/touch -- '/;s/$/'/" |sh
$( #BEGIN CGEN
   LC_ALL=C
   i= n='"$((i=((i=i+1)==10||i==39||i==47)>0?(i+1):i))"'
   printf '%b -_   ---___'  $(
   IFS=0; eval \
       printf '"\\\\%04o\\\\%04o "' "$(
       printf "$n"' "$i" '%s $(
       printf %.252d
#END
))"))
CGEN

우선 위의 명령이 다른 방법으로 더 쉽게 얻을 수있는 결과를 생성한다는 것을 인정할 것입니다. 그러나 다른 방법을 가능성이 함께 할 수있는 것뿐만 아니라 보여주지 것 $IFS조금 (병?) 상상력입니다.

따라서 첫 번째 비트는 매우 간단합니다.

  • tee 입력의 5 사본을 파이프로 보냅니다. CGEN

  • dd 블록 당 90 바이트의 줄 바꿈으로 입력을 차단하고 파이프를 …

  • sed2 개의 \newline 문자에서 해당 블록 중 2 개를 결합 '하고 결과를 작은 따옴표로 묶고 touch --모든 줄주기마다 문자열 을 앞에 추가하여 …

  • sh 그런 다음 모든 입력을 쉘 명령으로 실행합니다.

#CGEN비트하지만 … 음, 간단하게 …

  • 하단 printf은 252 0을 인쇄합니다

  • last from next는 252 개의 ''null-string 인수를 수신 하고 각각의 인쇄에 대해 $n그 뒤에 문자열 이 뒤 따릅니다." $i "

  • eval그 해석의 printf결과를 한 조각의 백 슬래시가 앞에 붙인 8 진수로 인쇄하기 전에 다음의 인수를 해석합니다.

  • 마지막 printf은 한 번에 8 진수 2의 바이트 값을 인쇄 한 다음 -_ ---___각 쌍 의 문자열 을 인쇄합니다.

  • $n$i10, 39 또는 47의 값을 건너 뛰는 것을 제외하고 모든 평가에 대해 1 씩 증가하는 방정식으로 초기화됩니다 ( 각각 ASCII 10 진수의 \newline, '작은 따옴표 및 /슬래시).

최종 결과는 작은 따옴표 (하나 이상의 sed s///문 을 피하기 위해 건너 뛰기 )/슬래시를 제외하고 1에서 255까지 내 문자 세트의 모든 바이트를 포함하는 실제로 추악한 파일 이름이 많은 디렉토리 입니다. 해당 파일 이름은 다음과 같습니다.

(set -- *; printf '%s\n\n##############\n\n%s\n' "${9}" "${34}")  | cat -A

   ---___ww -_   ---___xx -_   ---___yy -_   ---___zz -_   ---___{{ -_   ---___|| -_   ---$
$
___}} -_   ---___~~ -_   ---___^?^? -_   ---___M-^@M-^@ -_   ---___M-^AM-^A -_   ---___M-^BM-^B -_   ---___M-^CM-^C$
$
##############$
$
 -_   ---___M-ZM-Z -_   ---___M-[M-[ -_   ---___M-\M-\ -_   ---___M-]M-] -_   ---___M-^M-^ -_   ---___M-_M-_ -_$
$
---___M-`M-` -_   ---___M-aM-a -_   ---___M-bM-b -_   ---___M-cM-c -_   ---___M-dM-d -_   ---___M-eM-e -_   ---___$

이제이 파일들에 대한 데이터를 얻을 것이다 :

chksqz() ( LC_ALL=C sqz=$1
    set -- * ; set -f ; IFS= ; tc="$*"
    printf '#%s\n' \
        "There are $# files in this test directory." \
        "All filenames combined contain a total of ${#tc} bytes."
    IFS=$sqz ; set -- $* ; IFS= ; sc="$*"  
    printf "%s '$sqz'" \
        "#Of which ${#sc} bytes are not"\
        " and $((${#tc}-${#sc})) bytes are"
    set +f ; unset IFS
    printf ".\n#%s\n#Total:\t%d\n#Other:\t%d\n#'$sqz':\t%d\n" \
        "And to confirm these figures:" \
        $(  printf %s * | wc -c 
            printf %s * | tr -d "$sqz" | wc -c
            printf %s * | tr -dc "$sqz" | wc -c
))
chksqz '_ -'

산출

#There are 101 files in this test directory.
#All filenames combined contain a total of 17744 bytes.
#Of which 2692 bytes are not '_ -' and 15052 bytes are '_ -'.
#And to confirm these figures:
#Total: 17744
#Other: 2692
#'_ -': 15052

확인. 이제 마지막으로 행동하십시오.

ifsqz '_ -'
chksqz '_ -'

산출

#There are 101 files in this test directory.
#All filenames combined contain a total of 2692 bytes.
#Of which 2692 bytes are not '_ -' and 0 bytes are '_ -'.
#And to confirm these figures:
#Total: 2692
#Other: 2692
#'_ -': 0

성공! 당신은 자신을 볼 수 있습니다 :

ls

????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
???????????????????????????
???????????????????????????
???????????????????????????
????????????????????????????
????????????????????????????
????????????????
??????????????????????
????????????????????????
??????????????????????????
??????????????????????????
??????????????????????????
??????????????????????????
???????????????????????????
???????????????????????????
???????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
????????????????????????????
??????????????????????????
????????????????????????
????????????????????
??????????????????
????????????????????????????
??
????????????????????????????
??????????????????????????
????????????????????????????
????????????????????????????
????????????????????!!""##
??????????????????!!""##$$
????????????????!!""##$$%%
????????????!!""##$$%%&&((
????????!!""??##$$%%&&(())
$$%%&&(())**??++,,..0011
%%&&(())**++??,,..00112233
&&(())**++,,??..0011223344
))**++,,..??0011223344556
**++,,..00??11223344556677
22334455667788??99::;;<<==>>
445566778899??::;;<<==>>??@@
5566778899::;;??<<==>>??@@AA
6778899::;;<<??==>>??@@AABB
8899::;;<<==??>>??@@AABBCCDD
\\]]^^``aa??bbccddeeffgghh
]]^^``aabbc??cddeeffgghhii
^^``aabbccdd??eeffgghhiijj
??@@AABBCCDDEE??FFGGHHIIJJKK
AABBCCDDEEFF??GGHHIIJJKKLLM
BBCCDDEEFFGG??HHIIJJKKLLMMNN
CCDDEEFFGGHHII??JJKKLLMMNNOO
EEFFGGHHIIJJ??KKLLMMNNOOPPQQ
ffgghhiijjkk??llmmnnooppqqrr
gghhiijjkkllmm??nnooppqqrrss
iijjkkllmmnn??ooppqqrrsstt
jjkkllmmnnoo??ppqqrrssttuuvv
kkllmmnnooppqq??rrssttuuvvww
LLMMNNOOPPQQRR??SSTTUUVVWWXX
MNNOOPPQQRRSS??TTUUVVWWXXYY
OOPPQQRRSSTT??UUVVWWXXYYZZ[[
PPQQRRSSTTUUVV??WWXXYYZZ[[\\
RRSSTTUUVVWW??XXYYZZ[[\\]]
ssttuuvvwwxx??yyzz{{||}}~~??
ttuuvvwwxxyyz??z{{||}}~~????
uuvvwwxxyyzz{{??||}}~~??????
wwxxyyzz{{||??}}~~??????????
xxyyzz{{||}}~~??????????????
YYZZ[[\\]]^^??``aabbccddee
ZZ[[\\]]^^``??aabbccddeeff


답변

펄이있는 경우 일반적으로 이름이 바뀝니다. 넌 할 수있어:

> type rename
rename is /usr/bin/rename

이 스크립트가 어떻게 작성되는지 보여줍니다.

> cat /usr/bin/rename | head -n 5 #firt 5 lines for example
#!/usr/bin/perl -w
#
#  This script was developed by Robin Barker (Robin.Barker@npl.co.uk),
#  from Larry Wall's original script eg/rename from the perl source.
#

이 스크립트는 -i 플래그를 지원하지 않지만 (이것은 내 시스템의 버전입니다), 아마도 여러분의 지원합니다. 인수는 어떻습니까? 첫 번째는 PCRE 형식의 정규 표현식이며 필터처럼 작동하고 입력 이름을 출력 이름으로 수정합니다. 별표 ‘*’로 제공 한 입력 이름 목록입니다. 예를 들어,

> cd /tmp
> rename 's/ //g' *

실제 ‘*’에서 다음과 같이 확장 할 수 있습니다.

> rename 's/ //g' file1 file2 file3 othe files found in current directory

실제로 개수가 큰 파일이 있으면 함정에 빠지게됩니다. 쉘은 시스템이 허용하는 것보다 더 긴 라인을 확장합니다. find 또는 xargs를 사용하여 해결 방법을 수행 할 수 있습니다. ‘find’를 사용하면 이름이 디렉토리에있는 파일 수와 같은 횟수로 호출되므로 문제가 발생합니다. -r 옵션과 함께 xargs를 사용하는 것이 좋습니다. 하나의 이름 바꾸기 호출은 많은 파일을 수정합니다. 예를 들면 다음과 같습니다.

> ls | xargs -r rename 's/ //g'   #thats all, names will be appended at the end of this command.

마지막 문제는 무엇을 의미합니까?

's/ //g'

이것은 이름 수정을위한 정규식입니다. 첫 번째 ‘/’뒤에 공백이 있습니다. 이것은 감지되고 두 번째 ‘/’다음에 문자열로 대체됩니다. 그러나 세 번째 ‘/’로 끝나는 빈 문자열이 있으면 공백이 아무것도 대체되지 않습니다. 옵션 ‘g’는이 표현을 반복적으로 만듭니다. expression은 모든 이름을 처음부터 끝까지 걸으며 모든 공백을 감지합니다.

그러나 탭 문자 나 다른 ‘백색’문자가 있다면 어떻게해야합니까? 이 ‘\ s’를 대체합니다. 다른 불필요한 캐릭터는 무엇입니까? 간단히 표현에 추가하십시오. 예를 들어 대괄호로 모두 닫습니다.

's/[\s_-]//g'

이게 전부입니다. 유사성이 보입니까? 나는 당신이 man perlrequick과 man perlretut을 읽어야한다고 생각합니다. 이것은 정규 표현식이 어떻게 작동하는지 설명합니다. 필요한 경우 자체 스크립트에서 rename 명령을 사용할 수 있습니다.


답변

다음 sh쉘 루프는 기존 파일을 덮어 쓰지 않도록주의하면서 현재 디렉토리의 파일 이름에서 모든 공백, 밑줄 및 대시를 제거합니다.

for f in *; do
    test -f "$f" || continue
    nf=$( echo "$f" | tr -d ' _-' )
    ! test -e "$nf" && echo mv "$f" "$nf"
done

들어 bashksh, 그리고 논리와 좀 더 자세한되고 :

for f in *; do
    if [[ -f "$f" ]]; then
        nf=$( tr -d ' _-' <<<"$f" )
        if [[ ! -e "$nf" ]]; then
            echo mv "$f" "$nf"
        fi
    fi
done

echo원하는 작업을 수행 할 때 확실하게 제거하십시오 .

tr명령 (삭제됩니다 -d지정된 문자 세트에) 모든 문자를 ( ' _-'). 세트의 맨 처음이나 끝에 대시를 사용하는 것이 중요합니다. 그렇지 않으면 문자 범위로 해석됩니다.


답변