AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / unix / Perguntas / 555047
Accepted
Stefan
Stefan
Asked: 2019-12-02 05:09:15 +0800 CST2019-12-02 05:09:15 +0800 CST 2019-12-02 05:09:15 +0800 CST

Como mover o diretório para um diretório com o mesmo nome?

  • 772

Eu tenho um diretório foocom vários arquivos:

.
└── foo
    ├── a.txt
    └── b.txt

e quero movê-lo para um diretório com o mesmo nome:

.
└── foo
    └── foo
        ├── a.txt
        └── b.txt

Atualmente, estou criando um diretório temporário bar, mude foopara bare renomeie barpara foodepois:

mkdir bar
mv foo bar
mv bar foo

Mas isso parece um pouco complicado e eu tenho que escolher um nome para barisso que ainda não foi escolhido.

Existe uma maneira mais elegante ou direta de conseguir isso? Estou no macOS se isso importa.

directory mv
  • 9 9 respostas
  • 10768 Views

9 respostas

  • Voted
  1. Best Answer
    Kusalananda
    2019-12-02T05:59:26+08:002019-12-02T05:59:26+08:00

    Para criar com segurança um diretório temporário no diretório atual, com um nome que ainda não foi usado, você pode usar mktemp -dassim:

    tmpdir=$(mktemp -d "$PWD"/tmp.XXXXXXXX)   # using ./tmp.XXXXXXXX would work too
    

    O mktemp -dcomando criará um diretório no caminho fornecido, com o X-es no final do nome do caminho substituído por caracteres alfanuméricos aleatórios. Ele retornará o caminho do diretório que foi criado e armazenamos esse valor em tmpdir. 1

    Essa tmpdirvariável pode ser usada ao seguir o mesmo procedimento que você já está fazendo, barsubstituída por "$tmpdir":

    mv foo "$tmpdir"
    mv "$tmpdir" foo
    unset tmpdir
    

    O unset tmpdirno final apenas remove a variável.


    1 Normalmente, deve - se ser capaz de definir a TMPDIRvariável de ambiente para um caminho de diretório onde se deseja criar arquivos ou diretórios temporários com mktemp, mas o utilitário no macOS parece funcionar sutilmente diferente em relação a isso do que o mesmo utilitário em outros sistemas BSD, e criará o diretório em um local totalmente diferente. O acima, no entanto, funcionaria no macOS. Usar o um pouco mais conveniente tmpdir=$(TMPDIR=$PWD mktemp -d)ou mesmo tmpdir=$(TMPDIR=. mktemp -d)só seria um problema no macOS se o diretório temporário padrão estivesse em outra partição e o foodiretório contivesse muitos dados (ou seja, seria lento).

    • 22
  2. muru
    2019-12-02T19:30:11+08:002019-12-02T19:30:11+08:00

    No macOS, você pode instalar o renamecomando (um script Perl) usando o Homebrew:

    brew install rename
    

    Em seguida, usando o -p(a la mkdir) para fazer os diretórios necessários e -Aadicionar um prefixo:

    % mkdir -p foo/bar; touch foo/{a,b}.txt foo/bar/c.txt
    % rename -p -A foo/ foo/*
    % tree foo
    foo
    └── foo
        ├── a.txt
        ├── b.txt
        └── bar
            └── c.txt
    

    Execute com -npara mostrar as alterações sem renomear (dry-run):

    % rename -p -A foo/ foo/* -n
    'foo/a.txt' would be renamed to 'foo/foo/a.txt'
    'foo/b.txt' would be renamed to 'foo/foo/b.txt'
    'foo/bar' would be renamed to 'foo/foo/bar'
    

    Se você tiver arquivos de ponto, para que um simples *não os pegue, use outros métodos com rename:

    • Com o bash, use (mal) GLOBIGNOREpara *combinar arquivos de ponto:

      $ GLOBIGNORE=.; rename -p -A foo/ foo/* -n
      'foo/.baz' would be renamed to 'foo/foo/.baz'
      'foo/a.txt' would be renamed to 'foo/foo/a.txt'
      'foo/b.txt' would be renamed to 'foo/foo/b.txt'
      'foo/bar' would be renamed to 'foo/foo/bar'
      
    • Ou use findcom -print0e renamecom -0:

      % find foo -mindepth 1 -maxdepth 1 -print0 | rename -0 -p -A foo/ -n
      Reading filenames from STDIN
      Splitting on NUL bytes
      'foo/b.txt' would be renamed to 'foo/foo/b.txt'
      'foo/a.txt' would be renamed to 'foo/foo/a.txt'
      'foo/bar' would be renamed to 'foo/foo/bar'
      'foo/.baz' would be renamed to 'foo/foo/.baz'
      
    • 10
  3. bxm
    2019-12-03T05:15:14+08:002019-12-03T05:15:14+08:00

    Contanto que o conteúdo não seja suficiente para exceder os limites máximos dos parâmetros (e você não se importa com uma mensagem de erro "aceitável"), não precisa ser mais complicado do que isso:

    mkdir foo/foo
    mv foo/* foo/foo
    

    Alteração para lidar com arquivos ocultos:

    mkdir foo/foo
    mv foo/{.,}* foo/foo
    
    • 10
  4. Adam Trhon
    2019-12-02T14:35:55+08:002019-12-02T14:35:55+08:00

    Sugiro o contrário. Não mova o diretório, mas apenas seu conteúdo:

    .
    └── foo
        ├── a.txt
        └── b.txt
    
    mkdir foo/foo
    
    .
    └── foo
        ├── foo
        ├── a.txt
        └── b.txt
    
    cd foo
    mv $(ls | grep -v '^foo$') foo
    cd -
    
    .
    └── foo
        └── foo
            ├── a.txt
            └── b.txt
    

    Se você tem bash, você também pode fazer

    shopt -s extglob
    cd foo
    mv !(foo) foo
    cd -
    

    (conforme descrito aqui ) para evitar a execução de ls e grep.

    A vantagem desta solução é que é muito simples.

    Desvantagens (como apontado nos comentários):

    • Não é possível lidar com arquivos ocultos ( ls -Aconserta, mas não ls -a)
    • Não é possível lidar com nomes de arquivos contendo espaços (pode ser corrigido por aspas:mv "$(ls | grep -v '^foo$')" foo
    • Não é possível lidar com nomes de arquivos contendo novas linhas e outros caracteres especiais

    A maioria das desvantagens pode ser abordada usando algum truque bash, mas se for necessário lidar com nomes de arquivos malucos, é melhor usar uma abordagem mais robusta, conforme descrito em outras respostas.

    • 8
  5. roaima
    2019-12-02T05:20:35+08:002019-12-02T05:20:35+08:00

    Você já acertou em cheio. Você pode escolher um nome diferente para o diretório transitório, como o nome de destino com a data/hora atual em nanossegundos e nosso PID como um sufixo composto, mas isso ainda pressupõe que o diretório ainda não existe:

    dir=foo                         # The directory we want to nest
    now=$(date +'%s_%N')            # Seconds and nanoseconds
    mkdir "$dir.$now.$$"            # Create a transient directory
    mv -f "$dir" "$dir.$now.$$/"    # Move our directory inside transient directory
    mv -f "$dir.$now.$$" "$dir"     # Rename the transient directory to the name with which we started
    

    Se você quiser uma solução robusta garantida, eu faria um loop mkdiraté que fosse bem-sucedido

    now=$(date +'%s_%N')
    while ! mkdir -m700 "$dir.$now.$$" 2>/dev/null
    do
        sleep 0.$$
        now=$(date +'%s_%N')
    done
    
    • 6
  6. masterl
    2019-12-03T11:12:13+08:002019-12-03T11:12:13+08:00
    mkdir foo/foo && mv foo/!(foo) foo/foo
    

    Você precisa fazer cd no diretório onde está a pasta de origem (foo).

    Em seguida, execute o comando acima. Ele criará uma pasta chamada com o mesmo nome e moverá o conteúdo do pai foo para o diretório filho (exceto o diretório filho, daí a designação !).

    Se o diretório filho foo já existir, você pode ignorar a primeira parte e apenas executar o comando mv:

    mv foo/!(foo) foo/foo
    

    No MacOS, você pode precisar definir a opção extglob:

    shopt -s extglob
    
    • 6
  7. Hopping Bunny
    2019-12-04T20:04:36+08:002019-12-04T20:04:36+08:00

    Além das sugestões acima, você pode querer fazer check-out do rsync. Antes mesmo de começar, lembre-se sempre de usar a --dry-runopção com rsync antes de executá-la sem ele. O --dry-runvai dizer o que aconteceria na vida real.

    O rsync tem muitas opções que podem não apenas ajudar a copiar/mover arquivos, mas também acelerar o processo. Aqui está uma maneira de fazer o seu trabalho. A --remove-source-filesopção exclui os arquivos da fonte após o processo de movimentação (que na verdade é uma cópia seguida de uma exclusão). Observe que o comando rsync primeiro lê o conteúdo de foo, cria o diretório foo dentro do diretório existente chamado foo e inicia o processo de cópia. Ele termina com a exclusão dos arquivos de origem em foo. Cuidado: Preste atenção especial às barras para os nomes dos diretórios.

    Existem outras considerações, como muitos apontaram acima (como links simbólicos), mas a man rsyncajudará você a escolher as opções necessárias. Uma nota aqui: Como você solicitou uma solução para arquivos, isso funcionará. Isso não removerá os diretórios vazios que serão deixados para trás. Não conheço uma maneira de fazer isso sem uma etapa adicional, portanto, se alguém puder adicionar isso, obrigado antecipadamente!

    mkdir foo
    cd foo
    touch aaa bbb ccc ddd
    cd ..
    rsync -av --remove-source-files foo foo/
    

    a = modo de arquivo

    v = verboso

    • 2
  8. Tom
    2019-12-05T00:30:47+08:002019-12-05T00:30:47+08:00

    Simplesmente não toque em foo e você não terá problemas com nomes idênticos. Em vez disso, crie um diretório com o mesmo nome dentro dele e mova tudo para lá. Use o truque $_ para isso e && para torná-lo uma linha:

    cd foo && mkdir $_ && mv * $_
    

    Isso lançará um erro inofensivo ( mv: rename foo to foo/foo: Invalid argument ) que você pode ignorar.

    Vantagem sobre outras respostas: você só precisa digitar o nome do diretório uma vez, para não cometer erros de digitação.


    você pode misturar isso com outras respostas para um efeito ainda melhor:

    • mv {.,}* $_cuidará de arquivos ocultos (ao custo de mais erros que você também pode ignorar)
    • mv ./!(foo)evitará a mensagem de erro, mas somente se você definirshopt -s extglob
    • 2
  9. PowerLuser
    2019-12-24T09:52:06+08:002019-12-24T09:52:06+08:00

    Na verdade, isso é enganosamente simples e estou chocado que ninguém mais ofereceu essa resposta ainda, então aqui vou eu usando o seguinte, por exemplo ...

    $ mkdir foo
    $ mkdir bar
    $ mkdir ./bar/foo
    $ touch ./bar/foo/file1 && touch ./bar/foo/file2 && touch ./bar/foo/file3
    $ ls ./
    bar/ foo/
    $ ls ./bar/foo
    file1 file2 file3
    

    Agora vem a parte mágica

    $ mv ./bar/foo ./foo/
    $ ls ./foo/
    foo/
    $ ls ./foo/foo/
    file1 file2 file3
    

    Agora, por que isso funciona? Não posso dar a resposta mais precisa, pois sou apenas um neófito - mas entendo que se resume a como os /caracteres à direita são tratados nas pastas.

    Olhe atentamente para o comando mv

    $ mv ./bar/foo ./foo/

    Observe como a pasta de destino dos arquivos é especificada sem um final /, enquanto o destino que compartilha o nome da pasta de destino foi especificado usando um final /'. Este é o seu bilhete mágico e pode mordê-lo na bunda se você não estiver prestando atenção.

    Lamento não poder oferecer uma resposta mais elaborada do que essa no momento, mas talvez alguém com mais conhecimento fluente tome a liberdade de editar minha resposta.

    De qualquer forma, esta parece ser a solução mais simples e direta, com um único uso do lscomando e sem criação de pastas intermediárias.

    Espero que funcione para você, abraços!

    • 0

relate perguntas

  • Como posso copiar um diretório e renomeá-lo no mesmo comando?

  • Como ler múltiplos argumentos por linha para um comando bash?

  • Ubuntu 16.04: `mv` executado erroneamente com `~/*` como alvo e não consegue entender o resultado

  • Maneira mais rápida de determinar se o conteúdo do diretório mudou desde a última vez

  • Como mv .bin bin

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Possível firmware ausente /lib/firmware/i915/* para o módulo i915

    • 3 respostas
  • Marko Smith

    Falha ao buscar o repositório de backports jessie

    • 4 respostas
  • Marko Smith

    Como exportar uma chave privada GPG e uma chave pública para um arquivo

    • 4 respostas
  • Marko Smith

    Como podemos executar um comando armazenado em uma variável?

    • 5 respostas
  • Marko Smith

    Como configurar o systemd-resolved e o systemd-networkd para usar o servidor DNS local para resolver domínios locais e o servidor DNS remoto para domínios remotos?

    • 3 respostas
  • Marko Smith

    apt-get update error no Kali Linux após a atualização do dist [duplicado]

    • 2 respostas
  • Marko Smith

    Como ver as últimas linhas x do log de serviço systemctl

    • 5 respostas
  • Marko Smith

    Nano - pule para o final do arquivo

    • 8 respostas
  • Marko Smith

    erro grub: você precisa carregar o kernel primeiro

    • 4 respostas
  • Marko Smith

    Como baixar o pacote não instalá-lo com o comando apt-get?

    • 7 respostas
  • Martin Hope
    user12345 Falha ao buscar o repositório de backports jessie 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl Por que a maioria dos exemplos do systemd contém WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky Como exportar uma chave privada GPG e uma chave pública para um arquivo 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll status systemctl mostra: "Estado: degradado" 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim Como podemos executar um comando armazenado em uma variável? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S Por que /dev/null é um arquivo? Por que sua função não é implementada como um programa simples? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 Como ver as últimas linhas x do log de serviço systemctl 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - pule para o final do arquivo 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla Por que verdadeiro e falso são tão grandes? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis Substitua a string em um arquivo de texto enorme (70 GB), uma linha 2017-12-30 06:58:33 +0800 CST

Hot tag

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve