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 / 409298
Accepted
sdaau
sdaau
Asked: 2017-12-07 12:04:52 +0800 CST2017-12-07 12:04:52 +0800 CST 2017-12-07 12:04:52 +0800 CST

liste o diretório recursivamente, com subcaminho e nós de folha (arquivos) primeiro (para renomear em lote parte dos nomes de arquivos)?

  • 772

Antes de declarar isso uma duplicata, considere que eu precisaria disso por um motivo específico: renomear em lote (ou copiar para um novo nome) de uma estrutura de árvore que contém uma string comum em nomes de arquivos e diretórios. Aqui está um exemplo (experimentado no Ubuntu 14.04, então ferramentas GNU):

cd /tmp
mkdir myproj
mkdir -p myproj/myproj_AA/myproj_BB
touch myproj/myproj_AA/myproj_BB/myproj_CC.dat
mkdir myproj/myproj_AA/myproj_DD
touch myproj/myproj_AA/myproj_DD/myproj_EE.dat
mkdir -p myproj/myproj_XX/myproj_YY
touch myproj/myproj_XX/myproj_YY/myproj_ZZ.dat
mkdir -p myproj/myproj_XX/myproj_WW
touch myproj/myproj_XX/myproj_WW/myproj_QQ.dat
tree myproj # to visualise

Esta estrutura de diretórios se treeparece com isto:

myproj
├── myproj_AA
│   ├── myproj_BB
│   │   └── myproj_CC.dat
│   └── myproj_DD
│       └── myproj_EE.dat
└── myproj_XX
    ├── myproj_WW
    │   └── myproj_QQ.dat
    └── myproj_YY
        └── myproj_ZZ.dat

6 directories, 4 files

Portanto, gostaria que todas as entradas em myproj/, incluindo myproja própria, fossem renomeadas em myTESTprojvez de myproj(onde quer que ocorra como um nome). Então, primeiro preciso obter uma listagem com caminhos relativos em relação ao diretório atual - e então preciso classificá-lo de forma que os filhos mais externos (acho que isso é equivalente a arquivos com os nomes de caminho relativos mais longos, mas não tenho certeza) são os primeiros (porque se eu renomear/mv o diretório primeiro e, em seguida, tentar renomear um arquivo nele, provavelmente usará o antigo nome do diretório como primeiro argumento e falhará, pois o nome agora foi alterado).

Estou ciente de que é ls -R --group-directories-first myproj/necessário usar lsrecursivamente e agrupar diretórios primeiro, mas sua saída é assim:

$ ls -R --group-directories-first myproj/
myproj/:
myproj_AA  myproj_XX

myproj/myproj_AA:
myproj_BB  myproj_DD

myproj/myproj_AA/myproj_BB:
myproj_CC.dat

myproj/myproj_AA/myproj_DD:
myproj_EE.dat

myproj/myproj_XX:
myproj_WW  myproj_YY

myproj/myproj_XX/myproj_WW:
myproj_QQ.dat

myproj/myproj_XX/myproj_YY:
myproj_ZZ.dat

... ou seja, não é uma lista simples com subcaminhos, que eu poderia facilmente alimentarwhile read f; do ...

O mais próximo que cheguei é usar find:

$ find myproj/
myproj/
myproj/myproj_AA
myproj/myproj_AA/myproj_DD
myproj/myproj_AA/myproj_DD/myproj_EE.dat
myproj/myproj_AA/myproj_BB
myproj/myproj_AA/myproj_BB/myproj_CC.dat
myproj/myproj_XX
myproj/myproj_XX/myproj_YY
myproj/myproj_XX/myproj_YY/myproj_ZZ.dat
myproj/myproj_XX/myproj_WW
myproj/myproj_XX/myproj_WW/myproj_QQ.dat

Então, aqui eu tenho uma lista simples de subcaminhos, no entanto, é classificado primeiro o nó raiz em direção aos nós folha - e eu preciso primeiro dos nós folha. E estou tentando coisas como find myproj/ | sort -n, mas parece não fazer diferença. Então se eu fizer algo como:

$ find myproj/ | sort -n | while read f; do mv -v $f $(echo $f | sed 's/myproj/myTESTproj/g'); done
‘myproj/’ -> ‘myTESTproj/’
mv: cannot stat ‘myproj/myproj_AA’: No such file or directory
mv: cannot stat ‘myproj/myproj_AA/myproj_BB’: No such file or directory
mv: cannot stat ‘myproj/myproj_AA/myproj_BB/myproj_CC.dat’: No such file or directory
...

... então a renomeação recursiva pretendida falha imediatamente, pois o nó raiz (diretório) é renomeado primeiro e, portanto, todas as outras referências a ele são inválidas.

Então, como posso obter uma listagem recursiva adequada de um subdiretório com nós de folha primeiro, para usá-lo em uma renomeação em lote como esta?

bash sed
  • 3 3 respostas
  • 1230 Views

3 respostas

  • Voted
  1. Best Answer
    ilkkachu
    2017-12-07T12:35:30+08:002017-12-07T12:35:30+08:00

    Se você pretende apenas renomear, não basta que o conteúdo de cada diretório seja processado antes do próprio diretório, ou seja, não precisa de todas as folhas (de todos os diretórios) primeiro? find -depthfaz exatamente isso.

    $ mkdir -p a/b c/d
    $ find -depth
    ./a/b
    ./a
    ./c/d
    ./c
    .
    

    Então você pode usar find -exece Bash para renomear os arquivos:

    $ find -depth ! -name . -name "*myproj*" -execdir bash -c '
        for f; do mv "$f" "${f/myproj/myTESTproj}" ; done' bash {} +
    
    • 2
  2. roaima
    2017-12-07T12:41:55+08:002017-12-07T12:41:55+08:00

    Se você tiver a versão Perl do renamecomando instalada (às vezes conhecida como prename), isso funcionará para você

    find myproj -depth -name '*myproj*' -exec rename -n 's!(.*)myproj!$1myTESTproj!' {} +
    

    A -depthopção para findgarante que os filhos em qualquer diretório sejam listados antes do próprio diretório. O +sufixo para a -execação permite várias {}inserções para uma única chamada do comando especificado. Ao custo de eficiência reduzida, você pode substituí-lo por \;.

    Quando tiver certeza de que fará o que você deseja, remova -nou substitua por -v.

    • 1
  3. sdaau
    2017-12-07T12:04:52+08:002017-12-07T12:04:52+08:00

    Lembrei-me do que procurar depois de postar a pergunta - se os nós de folha são aqueles com os nomes de caminho relativos mais longos (o que não tenho certeza se é sempre verdade, mas parece estar pelo menos no exemplo OP), então um simplesmente precisa de uma maneira de classificar uma lista de strings por comprimento de string; infelizmente sortnão parece ter essa opção.

    Mas, encontrei https://stackoverflow.com/questions/5917576/sort-a-text-file-by-line-length-posing-spaces - e a partir daí, escolhi a perlsolução:

    $ find myproj/ | perl -e 'print sort { length($b) <=> length($a) } <>'
    myproj/myproj_AA/myproj_DD/myproj_EE.dat
    myproj/myproj_AA/myproj_BB/myproj_CC.dat
    myproj/myproj_XX/myproj_YY/myproj_ZZ.dat
    myproj/myproj_XX/myproj_WW/myproj_QQ.dat
    myproj/myproj_AA/myproj_DD
    myproj/myproj_AA/myproj_BB
    myproj/myproj_XX/myproj_YY
    myproj/myproj_XX/myproj_WW
    myproj/myproj_AA
    myproj/myproj_XX
    myproj/
    

    No entanto, a substituição trivial sed 's/myproj/myTESTproj/g'também não funciona aqui:

    $ find myproj/ | perl -e 'print sort { length($b) <=> length($a) } <>' \
    > | while read f; do mv -v $f $(echo $f | sed 's/myproj/myTESTproj/g'); done
    ‘myproj/myproj_AA/myproj_DD/myproj_EE.dat’ -> ‘myTESTproj/myTESTproj_AA/myTESTproj_DD/myTESTproj_EE.dat’
    mv: cannot move ‘myproj/myproj_AA/myproj_DD/myproj_EE.dat’ to ‘myTESTproj/myTESTproj_AA/myTESTproj_DD/myTESTproj_EE.dat’: No such file or directory
    ...
    

    ... então precisamos sed substituir apenas a última correspondência em uma linha , que é sed -E 's/(.*)myproj/\1myTESTproj/g':

    $ find myproj/ | perl -e 'print sort { length($b) <=> length($a) } <>' \
    | while read f; do mv -v $f $(echo $f | sed -E 's/(.*)myproj/\1myTESTproj/g'); done
    ‘myproj/myproj_AA/myproj_DD/myproj_EE.dat’ -> ‘myproj/myproj_AA/myproj_DD/myTESTproj_EE.dat’
    ‘myproj/myproj_AA/myproj_BB/myproj_CC.dat’ -> ‘myproj/myproj_AA/myproj_BB/myTESTproj_CC.dat’
    ‘myproj/myproj_XX/myproj_YY/myproj_ZZ.dat’ -> ‘myproj/myproj_XX/myproj_YY/myTESTproj_ZZ.dat’
    ‘myproj/myproj_XX/myproj_WW/myproj_QQ.dat’ -> ‘myproj/myproj_XX/myproj_WW/myTESTproj_QQ.dat’
    ‘myproj/myproj_AA/myproj_DD’ -> ‘myproj/myproj_AA/myTESTproj_DD’
    ‘myproj/myproj_AA/myproj_BB’ -> ‘myproj/myproj_AA/myTESTproj_BB’
    ‘myproj/myproj_XX/myproj_YY’ -> ‘myproj/myproj_XX/myTESTproj_YY’
    ‘myproj/myproj_XX/myproj_WW’ -> ‘myproj/myproj_XX/myTESTproj_WW’
    ‘myproj/myproj_AA’ -> ‘myproj/myTESTproj_AA’
    ‘myproj/myproj_XX’ -> ‘myproj/myTESTproj_XX’
    ‘myproj/’ -> ‘myTESTproj/’
    $ tree myTESTproj/
    myTESTproj/
    ├── myTESTproj_AA
    │   ├── myTESTproj_BB
    │   │   └── myTESTproj_CC.dat
    │   └── myTESTproj_DD
    │       └── myTESTproj_EE.dat
    └── myTESTproj_XX
        ├── myTESTproj_WW
        │   └── myTESTproj_QQ.dat
        └── myTESTproj_YY
            └── myTESTproj_ZZ.dat
    
    6 directories, 4 files
    

    Acho que isso faz o que eu quero - mas não tenho certeza se a suposição de nome de caminho mais longo == nó de arquivo de folha está sempre correta; e mesmo que seja - existe uma maneira mais fácil de fazer isso?


    EDIT: isso definitivamente falha em um caso de estrutura como esta:

    myproj/somespecdir/someotherdir/myproj_CC.dat
    myproj/myproj_AA/myproj_DD/myproj_EE.dat
    myproj/somespecdir/someotherdir
    myproj/myproj_AA/myproj_DD
    myproj/somespecdir
    myproj/myproj_AA
    myproj/
    

    ... ou seja, se a primeira ocorrência da substring a ser procurada e substituída no caminho renomeado também for a última (a única); e ocorre na lista antes de um caminho que possui várias ocorrências da substring.

    • 0

relate perguntas

  • exportar variáveis ​​​​env programaticamente, via stdout do comando [duplicado]

  • Problema estranho ao passar variáveis ​​do arquivo de texto

  • Enquanto a linha lê mantendo os espaços de escape?

  • ordem de substituição de processos `te` e `bash`

  • Execute um script muito lento até que seja bem-sucedido

Sidebar

Stats

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

    Matriz JSON para bash variáveis ​​usando jq

    • 4 respostas
  • Marko Smith

    A data pode formatar a hora atual para o fuso horário GMT? [duplicado]

    • 2 respostas
  • Marko Smith

    bash + lê variáveis ​​e valores do arquivo pelo script bash

    • 4 respostas
  • Marko Smith

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

    • 4 respostas
  • Marko Smith

    conexão ssh. Conexão X11 rejeitada devido a autenticação incorreta

    • 3 respostas
  • Marko Smith

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

    • 7 respostas
  • Marko Smith

    comando systemctl não funciona no RHEL 6

    • 3 respostas
  • Marko Smith

    rsync porta 22 e 873 uso

    • 2 respostas
  • Marko Smith

    snap /dev/loop em 100% de utilização -- sem espaço livre

    • 1 respostas
  • Marko Smith

    chave de impressão jq e valor para todos no subobjeto

    • 2 respostas
  • Martin Hope
    EHerman Matriz JSON para bash variáveis ​​usando jq 2017-12-31 14:50:58 +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
  • Martin Hope
    Drux A data pode formatar a hora atual para o fuso horário GMT? [duplicado] 2017-12-26 11:35:07 +0800 CST
  • Martin Hope
    AllisonC Como posso copiar um diretório e renomeá-lo no mesmo comando? 2017-12-22 05:28:06 +0800 CST
  • Martin Hope
    Steve Como as permissões de arquivo funcionam para o usuário "root"? 2017-12-22 02:46:01 +0800 CST
  • Martin Hope
    Bagas Sanjaya Por que o Linux usa LF como caractere de nova linha? 2017-12-20 05:48:21 +0800 CST
  • Martin Hope
    Cbhihe Altere o editor padrão para vim para _ sudo systemctl edit [unit-file] _ 2017-12-03 10:11:38 +0800 CST
  • Martin Hope
    showkey Como baixar o pacote não instalá-lo com o comando apt-get? 2017-12-03 02:15:02 +0800 CST
  • Martin Hope
    youxiao Por que os diretórios /home, /usr, /var, etc. têm o mesmo número de inode (2)? 2017-12-02 05:33:41 +0800 CST
  • Martin Hope
    user223600 gpg — o comando list-keys gera uid [ desconhecido ] depois de importar a chave privada para uma instalação limpa 2017-11-26 18:26:02 +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