Como posso converter todos os "x" s para "y" s em nomes de arquivos para um diretório específico a partir da linha de comando?

2

Eu estou nomeando arquivos, de hábito como um programador trabalhando em uma linha de comando do servidor, com sublinhados " _ " em vez de espaços " " - porque na linha de comando você tem que escapar de espaços - mas isso é desnecessário fora da linha de comando e está rapidamente ficando velho. Eu gostaria de manter tudo uniforme enquanto estiver mudando para espaços.

No "Terminal", estou pensando em como converter todos os "x" em "y" em nomes de arquivo para um diretório específico no Mac OS X? Note que "x" significa apenas qualquer coisa e com "y" simplesmente sendo um espaço.

Eu gostaria de fazer isso de forma recursiva, lidando com todos os subdiretórios em vez de apenas uma pasta por vez.

    
por Viziionary 11.02.2015 / 17:51

6 respostas

2

From the “Terminal,” I’m wondering how can I convert all “x”s to “y”s in filenames for a specific directory on Mac OS X? Note that “x” means just anything and with “y” simply being a space.

I’d like to do this recursively, handling all sub-directories rather than only one folder at a time.

Adaptando algumas das sed conceito de que @meatspace se refere a em seu comentário (que está localizado em esta página ) e adicionando find na mistura eu criei este script:

find . -type d -path '*/\.*' -prune -o -not -name '.*' -type f |\
  while read FULL_ITEM_PATH
  do
    FILE_DIRNAME=$(dirname "${FULL_ITEM_PATH}");
    FILE_BASENAME=$(basename "${FULL_ITEM_PATH}");
    mv "${FILE_DIRNAME}"/"${FILE_BASENAME}" "${FILE_DIRNAME}"/"$(echo $FILE_BASENAME | sed -e 's/_/ /g')";
  done

Isso usará find para localizar todos os arquivos do diretório atual em que você está - incluindo diretórios / arquivos secundários - e, em seguida, procurar sublinhados em nomes de arquivos ( _ ) e alterá-los para espaços ( ) desejado. O script ignora “arquivos de ponto” / “arquivos invisíveis” como .DS_Store via -prune -o -not -name '.*' e então a lógica do núcleo só age no nome real do arquivo — não no nome do diretório — separando o nome base do arquivo do nome do diretório.

Eu criei uma árvore de diretórios de teste na minha máquina Mac OS X 10.9.5 (Mavericks) com arquivos que contêm sublinhados ( _ ) em seus nomes - com alguns aninhados em um diretório filho - assim:

./foo_bar
./foo_bar_two
./foo_bar_two_three
./foo_bar_two_three_bleagh.txt
./nested/foo_bar
./nested/foo_bar_two
./nested/foo_bar_two_three
./nested/foo_bar_two_three_bleagh.txt
./nested_foo/foo_bar
./nested_foo/foo_bar_two
./nested_foo/foo_bar_two_three
./nested_foo/foo_bar_two_three_bleagh.txt

Em seguida, executei esse script e eles foram alterados automaticamente para usar espaços ( ) conforme desejado:

./foo bar
./foo bar two
./foo bar two three
./foo bar two three bleagh.txt
./nested/foo bar
./nested/foo bar two
./nested/foo bar two three
./nested/foo bar two three bleagh.txt
./nested_foo/foo bar
./nested_foo/foo bar two
./nested_foo/foo bar two three
./nested_foo/foo bar two three bleagh.txt

Enquanto o script funciona, se você quiser fazer uma simples “execução a seco” para ver quais arquivos o script atuaria, substitua o comando mv para echo desta forma:

find . -type d -path '*/\.*' -prune -o -not -name '.*' -type f |\
  while read FULL_ITEM_PATH
  do
    FILE_DIRNAME=$(dirname "${FULL_ITEM_PATH}");
    FILE_BASENAME=$(basename "${FULL_ITEM_PATH}");
    echo "${FILE_DIRNAME}"/"${FILE_BASENAME}" "${FILE_DIRNAME}"/"$(echo $FILE_BASENAME | sed -e 's/_/ /g')";
  done

O bom de usar o echo para depurar é que você também pode ver exatamente o que está acontecendo no núcleo do seu script. Assim, enquanto codifiquei esse roteiro para atender às necessidades exatas especificadas nesta pergunta, sinta-se à vontade para experimentar com ele para adaptá-lo a novas necessidades / ideias, se surgirem.

    
por 09.03.2015 / 21:11
0

Quando estiver no diretório relevante:

for f in in *; do echo mv "$f" "${f/_*_/ }"; done

Isso listará as alterações a serem feitas - remova echo quando quiser que ele realmente faça a renomeação. Como tudo * nix, há um milhão de maneiras de fazer isso, mas o acima é bem claro. Se você fizer essa tarefa com frequência, considere salvá-la em bin como um script.

    
por 11.02.2015 / 19:47
0

Para tarefas de renomeação em lote / complexas, use o comando renomear

Por exemplo, para substituir espaço por _ em todos os arquivos .txt na pasta atual

rename 's/ /_'  *.txt

Para renomear todos os arquivos recursivamente

find /path/to/target -type f -exec rename 's/ /_/' '{}' \;
    
por 12.03.2015 / 09:41
0

Eu provavelmente usaria o Perl para fazer isso.

#!/usr/bin/perl

use strict;
use warnings;

use File::Find;

sub rename_files {
   #skip directories
   return if -d $File::Find::name;

   my $newname = $File::Find::name;
   #turn underscores into space. 
      $newname =~ s/_/ /g; 
   rename $File::Find::name, $newname;
}

find ( \&rename_files, 'path_to_change' ); 
    
por 16.03.2015 / 14:30
-1

Que tal este forro? (Espero que colando meu comando aqui não estrague os espaços)

for f in 'find . -type f -name '*_*'' ; do echo mv "$f" "${f//_/ }"; done        

Parece funcionar quando eu tentei. (Você precisa remover esse eco quando estiver pronto)

Não faz renomeação do diretório. Eu acho que é isso que você queria? A recursão parece funcionar bem. Também lida com vários sublinhados corretamente.

    
por 11.03.2015 / 07:26
-2

Há mais de um shell:

david_koontz@Macbook: more ~/bin/rename

#!/bin/csh -f

if  ( $1 != "" && $2 != ""  ) then

    foreach file ( 'ls *$1*' )
    setenv target  'echo $file | sed s/"$1"/"$2"/'
        if ( -f $file ) then
            echo renaming $file to $target
            mv $file $target
        endif
    end
else
    echo "usage: $0 src_pattern_match  dest_pattern_substitution"
    exit -1
endif
exit 0

E para renomeação recursiva:

#!/bin/csh -f

    if  ( $1 != "" && $2 != ""  ) then

        # limit the depth search with -maxdepth:

        foreach file ( 'find . -maxdepth 8 -iname \*$1\* -type f -exec echo \{\} \;')
            setenv filehead $file:h
            setenv filetail $file:t
            setenv targettail 'echo $filetail | sed s/"$1"/"$2"/'
            echo renaming $file $filehead/$targettail
            mv $file $filehead/$targettail
        end
    else
        "usage: $0 src_pattern_match  dest_pattern_substitution"
        exit -1;
    endif

exit 0;

Para o recursive_rename, você poderia usar um opcional $ 3 para passar a profundidade máxima ou eliminar -maxdepth 8 , o que fornece um limite de profundidade recursivo.

Você poderia adicionar uma opção -i poderia ser adicionada a mv ou você poderia usar um argumento opcional para habilitar a renomeação interativa.

    
por 10.03.2015 / 08:03