É simples Não suporto quando as pessoas usam espaços ao nomear arquivos. Às vezes, destrói os comandos do console e torna a saída de ls feia.
O desafio é escrever um programa (apenas caracteres ascii) que
- renomeia todos os arquivos (incluindo diretórios) no diretório atual para versões com espaços removidos ou substituídos por '_'
- em caso de colisão, é necessário anexar um identificador exclusivo (até você)
- desce recursivamente em todos os subdiretórios
Você pode assumir nomes de caminho no estilo UNIX. Quem precisaria desse programa em uma máquina Windows?
Isso é código de golfe, o programa mais curto vence (caracteres #ascii). Como eu odeio tanto os espaços, cada espaço deve ser contado duas vezes.
Forneça seu idioma, pontuação, programa e uma breve descrição de como executá-lo.
O programa deve compilar e executar com um esforço razoável na minha máquina Linux.
EDIT: Como Etan solicitou uma estrutura de arquivos para teste, eis o script que atualmente uso para criar uma árvore de arquivos adequada:
#!/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
fonte
Respostas:
Coreutils Zsh + GNU - 48 bytes (1 espaço)
É estranho que você odeie espaços (ASCII), mas esteja bem com guias e novas linhas, mas acho que são necessários todos os tipos.
O zmv resolve muitos problemas de renomeação de arquivos de forma concisa (e apenas um pouco obscura). No entanto, insiste em que os alvos sejam únicos; embora você possa adicionar sufixos exclusivos com facilidade, adicionar um sufixo apenas se for necessário praticamente requer refazer todo o trabalho. Então, em vez disso, faço um loop manualmente e confio no GNU mv para anexar um identificador exclusivo em caso de colisão (
--backup
opção, além disso--no-target-directory
, caso um destino seja um diretório existente, caso contráriomv
, moveria a fonte dentro desse diretório).(od)
é um qualificador global para classificar a saída com os diretórios que aparecem após o conteúdo (como os do find-depth
).D
inclui arquivos de ponto na glob.:h
e:t
são modificadores de histórico semelhantes adirname
ebasename
.mv
reclama que foi chamado para renomear arquivos para si próprios, porque a glob inclui nomes de arquivos sem espaços. É a vida.Versão não destruída:
fonte
zmv
bombas antesmv
têm a chance de resolver colisões. Ok, estou fazendo isso manualmente. Acabará sendo exatamente do mesmo tamanho se eu pular arquivos de ponto e até salvar um caractere se não o fizer.Bash 116 bytes, 16 espaços
Não suprimi erros para obter mais alguns bytes. Isso não terá colisões.
Se um GNU não posix
find
puder ser esperado, isso poderá ser reduzido ainda mais:Bash 110 bytes, 15 espaços
A remoção de espaços em vez de substituí-los usa dois bytes a menos:
Bash 108 bytes, 15 espaços
Nota: se as guias puderem ser usadas em vez de espaços, será necessário apenas 1 espaço (aquele na regra de correspondência para substituição na linha 2).
Agradecimentos a Dennis por encontrar o erro entre aspas duplas (e fornecer a solução)
fonte
-depth
no GNU pode ser substituído por-d
, apesar de reclamar que está obsoleto. Não sei as regras do golfe, posso fazer isso?bash -c 'B=${0##*/}...' {} \;
que é mais curto.N
variável? Nunca é definida ...Python 180 bytes
apenas 2 espaços se você usar tab para recuo :-)
fonte
Se a ordem dos sufixos de arquivo colidido não precisar dar precedentes ao arquivo preexistente, o seguinte funcionará para mim:
bash / find / mv 84 bytes, 16 espaços
bash / find / mv 82 bytes, 14 espaços
Abraçado
&&
para salvar dois bytes de espaço.bash / find / mv 60 bytes, 11 espaços
Abaixa a proteção contra erros para obter erros do mv em arquivos que não têm espaço para começar.
Edit: Soltou as aspas de
{}
como lembrado por Dennis. Também é permitidofind
gritar sobre portabilidade e reprovação na versão mais curta, ondemv
já está gritando sobre mover um arquivo por cima de si.Editar 2: Adicionado
-T
aomv
comando para evitar o aninhamento de diretórios em vez de renomear, conforme indicado pelo pqnet. Expansão de chave usada ao custo de um caractere, usando apenas um espaço.fonte
-d
vez de-depth
e não precisa das aspas{}
.-d
conversa na resposta do pqnet, mas imaginei que, como estava silenciando osmv
gritos, evitaria osfind
gritos. Embora eu devesse encurtá-lo para o grito. E sim, eu sempre cito{}
por algum motivo, mesmo sabendo que não é necessário nesse caso. Força do hábito, eu acho.-T
opção paramv
evitar issoNodeJS - 209 bytes, 3 espaços em branco
fonte
node file.js
TypeError: Object #<Object> has no method 'exists'
. Adivinhe onde: está na linha 1! : DBash - 86 bytes
fonte
--backup
para--b
Bash + Perl
rename
64(
rename
é o script Perl no Debian e derivados, não o comando util-linux.)fonte
*
como deve ser{}
, apenas renomeia os arquivos cujo nome aparece no diretório atual. Isso não acrescenta um sufixo em caso de colisão. Você pode economizar um pouco ao omitir,-name "* *"
poisrename
ignora silenciosamente os arquivos cujo nome não é transformado.POSIX
sh
+ GNUfind
+ GNUmv
67 bytes ASCII + um espaço (literal)Não sei se ele se encaixa, mas com isso qualquer sequência de espaços é unida a um único
_
- eu gosto mesmo assim. Na verdade, qualquer sequência, exceto os espaços iniciais / finais que são - são automaticamente truncados (o que também é, penso eu, um comportamento benéfico) . Obrigado a Gilles por apontar isso.Isso apenas usa o separador de campo interno para separar os campos.
É bastante ... falador ...
...Oh cara. Eu sabia que a coisa da guia era barata, mas achei que era pelo menos inteligente. Agora estou atrasado para a festa ...
fonte
IFS
coisinha magia ...$expand
não (ex pand)) e na coisa ifsws mencionada. Veja aqui-exec
por-execdir
. Outra peculiaridadeIFS
que você não está mencionando é que os espaços finais são excluídos. Observe que, como outros observaram, você também precisa da-T
opçãomv
, para quando o destino de umamv
chamada for um diretório existente.sh -c 'mkdir -p ../newtree/"$0"; ln "$0"/* ../newtree/$0 {} \;
e outros globs em umfind -type d
comando para criar uma árvore espelhada de links físicos e depois operar com eles, mas estou pensando em escrever um código de golfe para uma operação de movimentação. Bom ponto sobre os espaços iniciais / finais, embora eu ache que esse também seja um comportamento que eu preferiria.zsh
a função incorporada,zmv
por exemplo.PHP,
147145 bytes,21 espaços-> 146função recursiva. Correr com
s(".");
Repita os
glob
resultados para o caminho especificado:fonte
Ruby 121
fonte
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
Python, 187
165, mais 22 pontos de penalidade para os espaços.
166, usando o truque de Emanuele :
Apenas um único espaço neste!
fonte
LiveScript - 166
(Substitua espaços por tabulações.)
Baseado no de nderscore versão otimizada da CPU1 's resposta .
fonte
Bash 4+ 111 bytes
fonte
Groovy, 139 caracteresde acordo com @ edc65 comment
Groovy, manipula colisões, 259 caracteres
fonte
POSIX (testado no zsh) + comandos básicos do Linux 151
fonte
$(ls -CR)
é completamente falso. A-c
opção é inútil e-R
gera arquivos sem o diretório deles, o que é inútil. Sua arquitetura fundamentalmente não manipula nomes de arquivos contendo novas linhas. Você precisaset -f
ou os nomes dos arquivos que contêm curingas explodirão.export
é inútil. Eu posso ver vagamente o que você está tentando fazer para unificar arquivos, mas a tubulação está errada.