Bash - Diretório recursivo / renomeação de arquivo

1

Eu tenho o seguinte script, que substituirá todos os espaços em arquivos e diretórios recursivamente:

################### SETUP VARIABLES #######################
number=0                    # Number of renamed.
number_not=0                # Number of not renamed.
IFS=$'\n'
array=( 'find ./ -type d' ) # Find catalogs recursively.


######################## GO ###############################
# Reverse cycle.
for (( i = ${#array[@]}; i; )); do
     # Go in to catalog.
     pushd "${array[--i]}" >/dev/null 2>&1
     # Search of all files in the current directory.
     for name in *
     do
             # Check for spaces in names of files and directories.
             echo "$name" | grep -q " "
             if [ $? -eq 0 ]
             then
                # Replacing spaces with underscores.
                newname='echo $name | sed -e "s/ /_/g"'
                if [ -e $newname ]
                then
                        let "number_not +=1"
                        echo " Not renaming: $name"
                else
                        # Plus one to number.
                        let "number += 1"
                        # Message about rename.
                        echo "$number Renaming: $name"
                        # Rename.
                        mv "$name" "$newname"
                fi
             fi
     done
     # Go back.
     popd >/dev/null 2>&1
done

echo -en "\n All operations is complited."

if [ "$number_not" -ne "0" ]
  then echo -en "\n $number_not not renamed."
fi

if [ "$number" -eq "0" ]
  then echo -en "\n Nothing been renamed.\n"
elif [ "$number" -eq "1" ]
   then echo -en "\n $number renamed.\n"
   else echo -en "\n Renamed files and catalogs: $number\n"
fi

exit 0

Funciona preenchendo um array com diretórios:

array=( 'find ./ -type d' ) # Find catalogs recursively.

Se eu quiser forçar esse script a funcionar em um diretório específico, posso fazer algo assim?

array=( 'find /my/start/directory/ -type d' ) # Find catalogs recursively.

Estou perguntando aqui (em vez de apenas executá-lo), pois quero verificar novamente se está correto, não quero renomear todos os arquivos no servidor por acidente!

    
por Lee 05.07.2018 / 17:34

1 resposta

2

Você pode testar seu script com a alteração proposta, comentando o comando mv e executando-o. Há algumas coisas demais acontecendo no script para eu dizer imediatamente que seria ok, mas se o script atual funcionar (você obviamente não tem nomes de diretório com novas linhas nelas, ou a matriz array seria quebrada , ou nomes começando com traços que potencialmente confundiriam mv e echo em alguns lugares) então eu arriscaria adivinhar que estaria tudo bem.

Para substituir espaços com sublinhados nos nomes de arquivos de diretórios e outros arquivos recursivamente:

topdir=.
find "$topdir" -depth -name "* *" -exec bash -c '
    for pathname do
        # $pathname will have at least one space in it
        newname=${pathname##*/}  # get basename
        newname=${newname// /_}  # replace spaces with underscores
        printf "Would move %s to %s\n" "$pathname" "${pathname%/*}/$newname"
        # mv "$pathname" "${pathname%/*}/$newname"
     done' bash {} +

Isso encontraria qualquer coisa dentro ou abaixo de $topdir que contivesse pelo menos um espaço em seu nome. Ele coletaria esses nomes de caminho e os daria a um script bash em linha. O script extrairia a parte do nome do arquivo de cada nome de caminho e substituiria os espaços por sublinhados. A operação mv real é comentada por segurança.

A opção -depth é necessária aqui, pois não queremos renomear os diretórios que ainda não visitamos. Com ele, find fará uma travessia em profundidade da hierarquia de diretórios.

Substituições de parâmetros usadas:

  • ${variable##*/} : remove tudo antes da última barra no valor de variable . Mais ou menos o mesmo que $( basename "$variable" ) .
  • ${variable%/*} : remove tudo após a última barra. Mais ou menos o mesmo que $( dirname "$variable" ) .
  • ${variable//pattern/replacement} : substitui tudo que combina pattern com replacement no valor de variable (essa é uma extensão bash )

Nenhuma verificação é feita para saber se o novo nome de arquivo já existe ou não. Isso pode ser feito facilmente no script bash interno com, por exemplo,

if [ -e "${pathname%/*}/$newname" ]; then
    printf "Will not rename %s, new name exists\n" "$pathname" >&2
else
    printf "Would move %s to %s\n" "$pathname" "${pathname%/*}/$newname"
    # mv "$pathname" "${pathname%/*}/$newname"
fi

Teste:

$ tree
.
|-- a directory
|   '-- yet another file
|-- script.sh
|-- some file
'-- some other file

1 directory, 4 files

$ sh script.sh
Would move ./some file to ./some_file
Would move ./some other file to ./some_other_file
Would move ./a directory/yet another file to ./a directory/yet_another_file
Would move ./a directory to ./a_directory

Relacionados:

por 05.07.2018 / 17:50