파일 이름에 공백이 있습니다.


61

간단하다. 사람들이 파일 이름을 지정할 때 공백을 사용할 때 설 수 없습니다. 때로는 콘솔 명령이 손상되어 ls의 결과가 나빠집니다.

문제는 프로그램 (아스키 문자 만)을 작성하는 것입니다.

  1. 현재 디렉토리의 모든 파일 (디렉토리 포함)을 공백이 제거되거나 '_'로 바뀐 버전으로 이름을 바꿉니다.
  2. 충돌시 고유 식별자를 추가해야합니다
  3. 모든 하위 디렉토리로 재귀 적으로 내려갑니다

UNIX 스타일 경로 이름을 가정 할 수 있습니다. 어쨌든 Windows 시스템에서이 프로그램이 필요한 사람은 누구입니까?

이것은 가장 짧은 프로그램이이기는 코드 골프입니다 (#ascii characters). 나는 공백을 너무 싫어하기 때문에 각 공백은 두 번 계산되어야합니다.

언어, 점수, 프로그램 및 운영 방법에 대한 간단한 설명을 제공하십시오.

이 프로그램은 내 리눅스 머신에서 합리적인 노력으로 컴파일하고 실행해야합니다.

편집 : Etan이 테스트를 위해 파일 구조를 요청함에 따라 적절한 파일 트리를 만드는 데 현재 사용하는 스크립트는 다음과 같습니다.

#!/bin/bash
rm -r TestDir

touchfiles()
{
    touch my_file
    touch my__file
    touch "my file"
    touch "my  file"
    touch " my_file  "
}

mkdir TestDir
cd TestDir

touchfiles

for dir in "Test Sub" Test_Sub "Te stSub" Te_stSub
do
    mkdir "$dir"
    cd "$dir"
    touchfiles
    cd ..
done

22
이것은 ASCII 문자없이 만든 솔루션을 요구합니다.
Dennis Jaheruddin

50
이제 공백을 배우고 싶습니다
BrunoJ

10
공백에서 @BrunoJ를 사용하려면 먼저 WS에서 파일 액세스 시스템을 개발해야합니다. 나는 그것이 실제 도전보다 더 도전적이라고 생각합니다.
Nzall

7
누군가가 C / C ++ 솔루션을 게시하기를 기다리는 동안 ZERO 공간이있는 x86 기계 코드로 16 진수로 훔치고 컴파일하고 게시 할 수 있습니다! [또는 아마 base64]
Mark K Cowan

10
파일 이름에서 밑줄이 싫어요. 대시를 사용하십시오.
Dr. Rebmu

답변:


10

Zsh + GNU coreutils — 48 바이트 (1 공백)

for x   (**/*(Dod))mv   -T  --b=t   $x  $x:h/${${x:t}// }

당신이 (ASCII) 공백을 싫어하지만 탭과 줄 바꿈에는 문제가되지 않는 것이 이상하지만 모든 종류가 필요합니다.

zmv많은 파일 이름 변경 문제를 간결하게 해결 합니다 (약간 모호하게). 그러나 고유 한 목표를 주장합니다. 고유 한 접미사를 쉽게 추가 할 수 있지만 접미사를 추가해야 할 경우에만 모든 작업을 다시 수행해야합니다. 따라서 대신 수동으로 루프하고 GNU mv 를 사용하여 충돌이 발생하는 경우 고유 식별자를 추가합니다 ( --backup옵션 --no-target-directory은 대상이 기존 디렉토리 인 경우 mv소스를 해당 디렉토리 내로 이동시키는 것과 같습니다).

(od)디렉토리는 내용 뒤에 나타나는 디렉토리 (find와 같은 )로 출력을 정렬 하는 glob 한정자-depth 입니다. D글로브에 도트 파일을 포함합니다. :h하고 :t있는 역사 수정은 유사 dirname하고 basename.

mvglob에는 공백이없는 파일 이름이 포함되므로 파일 이름을 자신으로 바꾸라는 호출이 있습니다. C'est la vie.

언 골프 버전 :

for x in **/*\ *(Dod); do
  mv --no-target-directory --backup=numbered $x ${x:h}/${${x:t}// /}
done

1
내 파일 이름이 전혀 바뀌지 않습니다!
M.Herzkamp

@ M.Herzkamp 아, zmv폭탄이 터지기 전에 mv충돌을 해결할 기회가 있습니다. 좋아, 나는 이것을 수동으로하고있다. 도트 파일을 건너 뛰면 정확히 같은 길이로 바뀌고 그렇지 않으면 문자를 저장합니다.
Gilles

1
이제 작동합니다. P :; : BTW) 나는 도전을 게시 할 때 아이러니하게도, 내가 공백을 배제하지 않았다 나는 정말 공간에 대한 원한을 가지고 한 번에 공간 페널티 킥 포함
M.Herzkamp을

13

배쉬 116 바이트, 16 공백

find . -depth -exec bash -c 'B=${0##*/}
M="${0%/*}/${B// /_}"
while [ -e "$M" ]
do M=$M.
done
mv "$0" "$M"' {} \;

몇 바이트를 더 얻기 위해 오류를 억제하지 않았습니다. 충돌이 없습니다.

POSIX가 아닌 GNU find를 예상 할 수 있다면 다음과 같이 더 단축 할 수 있습니다.

배쉬 110 바이트, 15 공백

find -d -exec bash -c 'B=${0##*/}
M="${0%/*}/${B// /_}"
while [ -e "$M" ]
do M=$M.
done
mv "$0" "$M"' {} \;

공백을 바꾸는 대신 공백을 제거하면 2 바이트가 덜 사용됩니다.

배쉬 108 바이트, 15 공백

find -d -exec bash -c 'B=${0##*/}
M="${0%/*}/${B// }"
while [ -e "$M" ]
do M=$M.
done
mv "$0" "$M"' {} \;

참고 : 공백 대신 탭을 사용할 수있는 경우 1 개의 공백 만 필요합니다 (2 행에서 대체를위한 일치 규칙의 공백).

큰 따옴표로 버그를 찾고 솔루션을 제공 한 Dennis에게 감사합니다.


11
추가 공간은 저를 찾을 수 있습니까 ??? ;-)
M.Herzkamp

@ M.Herzkamp 나는 복사하여 붙여 넣기 오류 였지만 실제로 있습니다. 2 점을 더 얻은 것 같아요. 또한, -depthGNU에 의해 대체 될 수 있습니다 -d그것이되지 않습니다 불평하지만,. 골프 규칙에 대해 잘 모르겠습니다. 그렇게 할 수 있습니까?
pqnet

2
작동하는 한 허용합니다. 향후 버전에서 더 이상 사용되지 않을 예정인 경우,이 답변으로 돌아와서 정확하지 않은 것으로
하향 조정

2
파일 이름에 큰 따옴표가 포함되어 있으면 제대로 작동하지 않습니다. 이 문제를 해결하려면 bash -c 'B=${0##*/}...' {} \;대신 더 짧게 사용할 수 있습니다 .
Dennis

3
나는 그 사람이 될 것 같아요, N변수는 무엇입니까? 그것은 정의되지 않았습니다 ...
Steven Penny

9

파이썬 180 바이트

from    os  import*
t,c,h='.',chdir,path
def g(p):
    c(p)
    for x   in  listdir(t):
        if h.isdir(x):g(x)
        n=x.replace(' ','')
        while h.exists(n):n+=t
        if' 'in x:rename(x,n)
    c(t*2)
g(t)

들여 쓰기에 탭을 사용하는 경우 2 칸만 :-)


다른 답변의 대부분은 공백 대신 탭을 사용하여 점수를 향상시킬 수 있다고 생각합니다.
kasperd

그러나 제출이 공백을 사용합니까? (+1 코드 작업을위한)
M.Herzkamp

나는 대답에서 탭 문자를 att하는 방법을 모른다 ...
Emanuele Paolini

2
:-) 탭으로 대체
에마 Paolini는

3
얼마나 못생긴 ... 글쎄, 나는 그것을 요구 한 것 같아 :(
M.Herzkamp

5

충돌 된 파일 접미어의 순서가 기존 파일에 선행 할 필요가없는 경우 다음이 작동합니다.

bash / find / mv 84 바이트, 16 공백

find -depth -execdir bash -c '[ "${0//[^ ]}" ] && mv -{T,--b=t} "$0" "${0// }"' {} \;

bash / find / mv 82 바이트, 14 공백

find -depth -execdir bash -c '[ "${0//[^ ]}" ]&&mv -{T,-b=t} "$0" "${0// }"' {} \;

&&두 개의 공간 바이트를 절약하기 위해 안기고 있습니다.

bash / find / mv 60 바이트, 11 공백

find -d -execdir bash -c 'mv -{T,-b=t} "$0" "${0// }"' {} \;

오류 보호를 삭제하여 공백이없는 파일의 mv에서 오류를 가져옵니다.

편집 : {}Dennis가 생각 한대로 인용문을 삭제했습니다 . 또한 파일을 맨 위로 옮기는 것에 대해 이미 비명을 지르는 find가장 짧은 버전에서 이식성과 폐기에 대해 비명을지를 수있었습니다 mv.

편집 2 : 추가 -Tmvpqnet에 의해 지적 중첩 디렉토리 대신 이름 변경을 방지하기 위해 명령. 하나의 공백을 사용하는 대신 한 문자의 비용으로 중괄호 확장을 사용했습니다.


-d대신 사용할 수 있으며 -depth주위에 따옴표가 필요하지 않습니다 {}.
Dennis

@ 데니스 예. 나는 -dpqnet의 답변에 대한 대화를 보았지만 mv비명을 지르고 나서 find비명을 피할 것이라고 생각했습니다 . 나는 아마도 비명을 지르기 위해 그것을 단축시켜야 할 것입니다. 그리고 네, 이 경우에 당신이 필요하지 않다는 {}것을 알고 있지만 항상 어떤 이유로 든 인용 합니다 . 내가 생각하는 습관의 힘.
Etan Reisner

1
디렉토리 이름에서 충돌이 발생하면 디렉토리 이름이 다른 디렉토리에 배치되고 공백이 제거되지 않습니다. 이것을 피하기 위해 -T옵션을 사용하십시오mv
pqnet

이것은 효과가 있으며, 부록에서 당신에게 달려 있다고 도전했습니다. +1
M.Herzkamp

4

NodeJS – 209 바이트, 3 개의 공백

s=require('fs');function a(d){s.readdirSync(d).forEach(function(f){f=d+'/'+f;i=0;r=f;if(/ /.test(f)){r=f.replace(' ','');while(s.existsSync(r))r+=i++;s.renameSync(f,r)}s.statSync(r).isDirectory()&&a(r)})}a('.');

node.js에 익숙하지 않습니다. 어떻게 실행합니까?
M.Herzkamp

Node 실행 파일 nodejs 가 필요합니다 . 파일에 저장하고 다음을 실행하십시오node file.js
cPu1

7
예외가 발생 TypeError: Object #<Object> has no method 'exists'합니다. 어디를 맞춰봐 : 그것은 1 행에있다! : D
M.Herzkamp

나는 그것을 테스트했다. 어쨌든, 나는 그것의 동기 상대로 대체되었습니다. 당신은 지금 시도 할 수 있습니까?
cPu1

1
버전 0.6.12 만 설치되어 있습니다. 문제 일 수 있습니다.
M.Herzkamp

2

배쉬-86 바이트

find    .   -d|while    IFS=""  read    f;do    t=${f##*/};mv   --b=t   -T  "$f"    "${f%/*}"/${t// /};done

아차,보고해야합니다
Subbeh

2
또한, 공백은 두 번 계산됩니다 ;-)
M.Herzkamp

공백이 두 번 계산된다는 것은 정확히 무엇을 의미합니까?
Subbeh

1
당신은 축약하여 문자를 많이 절약 할 수 있습니다 --backup--b

1
예, 이제 테스트 세트에서도 작동합니다! +1
M.Herzkamp

2

배쉬 + 펄 rename64

( renameutil-linux 명령이 아닌 데비안 및 파생어에 대한 Perl 스크립트입니다.)

find . -depth -name "* *" -execdir rename 'y/ /_/' * \;

11
"my file.txt"및 "my_file.txt"가 모두 있으면 어떻게됩니까?
M.Herzkamp

1
오 사실 .. 곧 작업
german_guy

1
*해야 {}그것은이는 이름이 현재 디렉토리에 표시되는 파일 이름을 변경 약자로,. 충돌시 접미사를 추가하지 않습니다. 이름이 변환되지 않은 파일을 자동으로 무시 -name "* *"하므로 생략하면 상당히 절약 할 수 rename있습니다.
Gilles

2

POSIX sh+ GNU find+ GNU mv67 ASCII 바이트 + 1 (문자) 공간

find    -d  -exec   sh  -cf 'IFS=\ ;IFS=_   set $0;mv   --b=t   "$0"    "$*"'   {}  \;

나는 그것이 맞는지 모르겠지만, 이것으로 어떤 일련 의 공백도 단일로 생략됩니다 _-어쨌든 그것을 좋아합니다. 실제로 모든 시퀀스 이지만 선행 / 후행 공백은 자동으로 잘립니다 (또한 유익한 동작이라고 생각합니다) . 이것을 지적 해 주신 Gilles에게 감사합니다.

내부 필드 구분 기호를 사용하여 필드를 구분합니다.

상당히 ... 뻔뻔스럽고 ...

... 오. 나는 탭이 싸다는 것을 알았지 만 적어도 영리하다고 생각했습니다. 이제 파티에 늦었 어


이것은 의도 한대로 테스트 세트에서 작동하지만 도전이 요구하는 것은 아닙니다. 그래도 새로운 것을 배우기 때문에 좋아합니다. 나는이 IFS마술 에 대해 읽어야 할 것 같다 ...
M.Herzkamp

1
@ M.Herzkamp-공백 설정 여부에 따라 ifs가 다르게 동작합니다. 그것은 단지 확장에 작동하는지 - 그들은 그 두 가지 기본 특성을 이해하지 않기 때문에 대부분의 사람들은 싫어 ( $expand하지 (예를 PAND)) 와 ifsws 일이 방금 언급. 여기를
mikeserv

이름에 공백이있는 디렉토리 내의 파일 이름은 바뀌지 않습니다. 수정은로 대체 -exec됩니다 -execdir. IFS당신이 언급하지 않은 또 다른 단점은 후행 공백이 삭제된다는 것입니다. 다른 사람들이 알다시피 , 호출 의 대상이 기존 디렉토리 인 경우에 대한 -T옵션도 필요합니다 . mvmv
Gilles

@Gilles-선호 sh -c 'mkdir -p ../newtree/"$0"; ln "$0"/* ../newtree/$0 {} \;하는 것은 find -type d명령 에 다른 글로브 를 사용하여 하드 링크의 미러 트리를 만든 다음 그에 대해 작업하는 것이지만 이동 작업을 위해 코드 골프를 작성하는 것은 두 번째 추측입니다. 앞 / 뒤 공간에 대해 좋은 점은 제가 선호하는 행동이라고 생각합니다.
mikeserv

@Gilles는 -하지만 그건 그렇고, 그것은 아니다 특질 - 그것은 의도 된 표준 제어 동작을. 필드 - 분할 부분은 단어가 포함되지 않은 쉘 사양에 거의 중 하나입니다 지정 또는 구현 정의 . 예 를 들어 zsh내장 기능 zmv 에 대해서는 그러한 보장이 없습니다 .
mikeserv

2

PHP, 147 145 바이트 2 1 공간 (S) -> 146

function    s(){foreach(glob("*")as$n){is_dir($n)&&chdir($n)&s()|chdir("..");if($n<$r=strtr($n," ",_)){while(file_exists($r))$r.=_;rename($n,$r);}}}

재귀 함수. 로 실행s(".");

glob주어진 경로에 대한 결과를 반복 합니다 :

  • 디렉토리 인 경우 재귀
  • 공백을 밑줄로 바꾸십시오
  • 문자열이 다른 경우
    • 새 파일 이름을 사용하는 동안 밑줄을 추가하십시오
    • 파일 / 디렉토리 이름 바꾸기

php는 서버의 파일 이름을 바꿀 것입니다 ... 이제 고객이 귀하의 사이트를 방문 할 때마다 파일 이름을 변경하는 방법이 궁금합니다. : D
M.Herzkamp

1

루비 121

require 'find'

Find.find('.') do |file|
  if file.chomp.match(/ /)
    File.rename(file, file.gsub(/ /, '_'))
  end
end

6
Code Golf에 오신 것을 환영합니다! 이러한 코드 골프 과제 에서 아이디어 는 가장 적은 수의 문자를 사용하는 것입니다. 즉, 빈 줄과 탭을 확실히 제거하고 변수 이름을 한 문자로 만들 수 있지만 사람들은 문자 수를 줄이는 모든 종류창의적인 방법 을 찾습니다 .
아니 찰스

디렉토리가 비어 있지 않다는 오류가 발생합니다.gam3.rb:5:in `rename': Directory not empty - ./Te stSub or ./Te_stSub (Errno::ENOTEMPTY) from gam3.rb:5 from /usr/lib/ruby/1.8/find.rb:39:in `find' from /usr/lib/ruby/1.8/find.rb:38:in `catch' from /usr/lib/ruby/1.8/find.rb:38:in `find' from gam3.rb:3
M.Herzkamp

1

파이썬, 187

165 + 공백에 22 페널티 포인트.

from os import*
u='_';j=path.join
for t,d,f in walk('.',0):
 for z in f+d:
  n=z.replace(' ',u)
  if n!=z:
   while path.exists(j(t,n)):n+=u
   rename(j(t,z),j(t,n))

166, Emanuele의 \ t 트릭 사용 :

이 공간에는 하나의 공간 만 있습니다!

from    os  import*
u='_';j=path.join
for t,d,f   in  walk('.',0):
    for z   in  f+d:
        n=z.replace(' ',u)
        if  n!=z:
            while   path.exists(j(t,n)):n+=u
            rename(j(t,z),j(t,n))

이것은 나를 위해 작동합니다. +1
M.Herzkamp

라인 및 사용 탭의 시작 부분에 공백을 제거 - 그들은 공백이 너무 한 번만 계산되지 않습니다
chill0r

@ chill0r 이것이 두 번째 버전입니다. 모든 공백은 탭을 제외하고 탭으로 대체됩니다 (단, 공백으로 공백을 표시하는 경우 제외).
Henry Keiter

1

라이브 스크립트-166

공백을 탭으로 바꾸십시오.

(a=->(s=require \fs)readdirSync(it)map (f)->f=it+'/'+f;r=f.replace /\s/g,i='';(while f!=r&&s.existsSync r=>r+=i++);s.statSync(f)isDirectory(s.renameSync f,r)&&a r) \.

를 기반으로 nderscore의 최적화 된 버전CPU1대답 .


공장! +1이 게시물을 정리하기 위해 먼저 내 의견을 삭제하겠습니다.
M.Herzkamp

0

배쉬 4+ 111 바이트

shopt -s dotglob globstar
for f in **
do
n=${f// /}
while [[ $f != $n && -e $n ]]
do n+=1
done
mv "$f" $n
done

1
다른 여러 항목과 동일한 문제 : 상위 디렉토리의 공백을 바꾸면 mv에서 찾을 수 없습니다. 또한 이송 방향을 변경해야합니다. 그렇지 않으면 디렉토리 이름을 바꾸면 mv가 파일을 찾을 수 없습니다.
M.Herzkamp

0

그루비, 139 자

def c
c={
f->
def g=new File(f.parent,f.name.replaceAll('\\s',''))
f.renameTo(g)
!g.directory ?: g.eachFile(c)
}
new File('.').eachFile(c)

@ edc65 의견에 따르면

그루비, 충돌 처리, 259 자

def c
c={
p,l,f->
def g=new File(p,f.name.replaceAll('\\s',''))
f==g?:
(g.exists()?f.renameTo(g.toString()+l.indexOf(f.name)):f.renameTo(g))
!g.directory?:g.eachFile(c.curry(g,g.list().toList()))
}
def r=new File('.')
r.eachFile(c.curry(r,r.list().toList()))

1
충돌은 처리하지 않습니다.
edc65

상위 디렉토리를 변경하기 전에 파일 이름을 바꾸고 상위 디렉토리의 공백을 바꾸지 않아야합니다.
M.Herzkamp

괜찮습니다
로그인

0

POSIX (zsh에서 테스트) + 기본 Linux 명령 151

export IFS='
'
for f in $(ls -R1);do export n=$(echo $f|tr ' ' '_');yes n|mv $f $n || yes n|mv $f `echo $n;echo $f|md5sum`
done

@ M.Herzkamp 수정.
LinGeek

여러 가지 : ls -cR에서 내보내기 IFS와 c의 기능은 무엇입니까? --reply 옵션에 필요한 mv 버전은 무엇입니까? (8.13이 있으며 옵션을 인식하지 못합니다). 또한 점수를 높이려면 변수 이름을 줄여야합니다.
M.Herzkamp

c는 공백을 개행 문자로 바꿉니다. IFS는 공백이 분리 자로 중지됩니다. --reply는 이전 버전에서 왔으며 수정하려고합니다.
LinGeek

1
5 행에서 두 번째 mv가 누락 되었습니까? 그리고 그 줄에 하나의 반향이 잘못되었다고 생각합니다.
M.Herzkamp

1
$(ls -CR)완전히 가짜입니다. 이 -c옵션은 쓸모가 없으며 -R디렉토리가없는 파일을 가져옵니다. 아키텍처는 기본적으로 개행을 포함하는 파일 이름을 처리하지 않습니다. set -f와일드 카드가 포함 된 파일 이름 이 필요 하거나 그렇지 않으면 폭발합니다. export쓸모가 없습니다. 파일을 균일화하기 위해 무엇을하려고하는지 모호하게 볼 수 있지만 배관이 잘못되었습니다.
Gilles
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.