Como renomear o diretório de todas as contas de usuário

1

Digamos que mais usuários tenham um diretório tmp em seu diretório inicial. Desejo renomear cada diretório tmp em cada diretório inicial do usuário. Qual é a maneira mais fácil?

Algo parecido com isto:

sudo mv /home/*/tmp /home/*/temp

não está bem.

E algo assim:

for dir in /home/*; do
    if [ -d $dir/tmp ]; then
        mv $dir/tmp $dir/temp
    fi
done

parece demais.

    
por Radu Rădeanu 23.08.2013 / 19:44

6 respostas

4

O Perl vem com um comando rename(1) instalado na maioria dos sistemas Linux. Em sistemas baseados em Debian, ele está em /usr/bin e, nesse caso, você o usaria assim:

$ rename 's/tmp$/temp/' /home/*/tmp

O primeiro argumento é uma expressão perl que atua nos argumentos subseqüentes gerando um novo nome. Cada um é então renomeado de acordo com o resultado dessa expressão.

Se um diretório inicial já tiver um arquivo / diretório chamado temp , você só receberá um erro para esse diretório e rename continuará:

/home/c/tmp not renamed: /home/c/temp already exists

Você pode executá-lo primeiro com o sinal -n para ver qual renomeação faria sem realmente fazer isso e verificar se tudo está correto. Em seguida, elimine o -n e deixe-o fazer o seu trabalho.

    
por 24.08.2013 / 00:26
3
sudo find /home -maxdepth 2 -type d -name 'tmp' -execdir mv {} temp \;

Aqui, maxdepth garante que você procure apenas até dois níveis no diretório atual. E execdir especifica que o comando subseqüente será executado mudando para o local onde o arquivo encontrado está.

Fonte: link

    
por 23.08.2013 / 20:11
3

A única maneira que posso pensar em encurtar a segunda opção na sua pergunta é:

for dir in /home/*;do
    [ -d $dir/tmp ] && mv -n $dir/t{,e}mp
done

mas isso elimina um pouco a legibilidade. Observe que t{,e}mp é expandido pelo shell nas duas palavras tmp e temp . Portanto, a linha de comando seria expandida para mv <contents of $dir>/tmp <contents of $dir>/temp . Em geral, o shell expande prefix_{a,b,c}_suffix para prefix_a_suffix prefix_b_suffix prefix_c_suffix . Uma posição vazia como a primeira em {,e} é expandida em uma string vazia.

Você também pode fazer algo semelhante com perl :

perl -e '
    @a=grep {-d} glob "/home/*/tmp";
    map { rename $_ => $_=~ s/tmp\Z/temp" } @a
'

mas ainda afirmo que sua versão original foi boa o suficiente.

Editar

Adicionada a opção -n a mv para garantir que não vai atrapalhar $dir/temp se existir, como observado no comentário de Michael Kjörling sobre a questão. A versão Perl irá espancar temp se existir.

    
por 23.08.2013 / 20:08
1

Se o seu sistema tiver um comando getent e uma mv que aceita a opção -T , você poderá fazer:

getent passwd |
  while IFS=: read -r x x uid x x home x; do
    [ "$home" = / ] ||
    [ "$home" = /var ] ||
    [ "$uid" -lt 500 ] ||
    [ ! -d "$home/tmp" ] ||
    find "$home/tmp" -prune -user "$uid" -exec sh -xc '
      mv -T -- "$1" "${1%/*}/temp"' sh {} \;
done

Ou seja, listamos o banco de dados do usuário para recuperar o diretório uid e home. Excluímos os usuários que têm / ou /var como seus diretórios pessoais (pois não queremos renomear /tmp e /var/tmp ) e usuários cujo uid esteja abaixo de 500 (como na maioria dos sistemas, esses são usuários do sistema).

Em seguida, consideramos apenas $home/tmp se o proprietário for o usuário em questão (novamente, para evitar mover o arquivo / diretório errado).

A opção -T como encontrada no GNU mv está no caso de $home/temp já existir, para evitar mover tmp dentro dela.

Observe que qualquer falha de mv gerará uma mensagem de erro, mas o status de saída da falha será perdido.

    
por 23.08.2013 / 22:31
1

Produza as declarações de movimento e avalie-as de uma só vez:

ls -d /home/*/tmp | sed 's/.*t/mv &mp &e/' | sh -xv
    
por 24.08.2013 / 00:28
1

Se você está apenas procurando por uma versão mais compacta do seu loop for, você pode fazê-lo um pouco mais compacto da seguinte forma:

$ for dir in /home/*/tmp; do [ -d $dir ] && mv $dir ${dir/%tmp/temp/};done

Isso usará o recurso de globbing do bashes para encontrar todos os diretórios e arquivos que correspondam à expressão regular /home/*/tmp . Em seguida, ele testa para ver se é um diretório ou não, se é um diretório, mova-o. O último bit ${dir/%tmp/temp/} pesquisa e substitui o conteúdo da variável $dir e substitui tmp por temp . Esta pesquisa & substituir é feito apenas uma vez da direita para a esquerda, protegendo assim qualquer coisa além do diretório tmp .

Exemplo

Digamos que eu tenha essa estrutura de diretórios falsa:

$ tree -p
.
'-- [drwxrwxr-x]  home
    |-- [drwxrwxr-x]  sam1
    |   '-- [drwxrwxr-x]  tmp
    |-- [drwxrwxr-x]  sam2
    |   '-- [drwxrwxr-x]  tmp
    |-- [drwxrwxr-x]  sam3
    |   '-- [drwxrwxr-x]  tmp
    '-- [drwxrwxr-x]  sam4
        '-- [-rw-rw-r--]  tmp

Agora, se usarmos uma versão modificada do nosso comando acima, o que simplesmente ecoa o comando mv em vez de executá-lo, podemos ver o que ele fará:

$ for dir in home/*/tmp; do [ -d $dir ] && echo "mv $dir ${dir/%tmp/temp/}";done

mv home/sam1/tmp home/sam1/temp/
mv home/sam2/tmp home/sam2/temp/
mv home/sam3/tmp home/sam3/temp/

OBSERVAÇÃO: O início / está intencionalmente ausente, para que eu possa executar este teste a partir de um diretório de amostra que eu configurei.

renomeia em vez de mv

Você também pode solicitar a ajuda do comando rename em vez de mv . Isso muda o exemplo ligeiramente:

 $ for dir in /home/*/tmp; do [ -d $dir ] && rename $dir ${dir/%tmp/temp/};done
    
por 23.08.2013 / 23:34