Appiattimento della struttura delle cartelle


8

Ho questa struttura di cartelle:

├── foo1
   ├── bar1.txt
   └── bar2.txt
├── foo2
   ├── bar3.txt
   └── bar4 with a space.txt
└── foo3
    └── qux1
        ├── bar5.txt
        └── bar6.txt

che vorrei appiattire in questo, con un carattere di sottolineatura tra ogni livello di cartella:

├── foo1_bar1.txt
├── foo1_bar2.txt
├── foo2_bar3.txt
├── foo2_bar4 with a space.txt
├── foo3_qux1.bar6.txt
└── foo3_qux1_bar5.txt

Mi sono guardato intorno e non ho trovato alcuna soluzione che funzioni, soprattutto penso che il mio problema abbia due particolarità: potrebbe esserci più di un livello di cartella all'interno di quello root e anche perché alcuni file potrebbero avere spazi.

Qualche idea su come realizzare questo in bash? Grazie!

Modifica : esecuzione gleen jackman proposta di risposta Ottengo questo:

inserisci qui la descrizione dell'immagine

Ci sono due trattini bassi per la cartella di primo livello. Qualche idea su come evitare questo o semplicemente rinominarlo in modo che sia solo un trattino basso? Grazie.

Risposte:


15
find */ -type f -exec bash -c 'file=${1#./}; echo mv "$file" "${file//\//_}"' _ '{}' \;

rimuovi echose sei soddisfatto che funzioni. Non preoccuparti che i comandi con eco non mostrino le virgolette, lo script gestirà i file con spazi correttamente.

Se si desidera rimuovere le sottodirectory ora vuote:

find */ -depth -type d -exec echo rmdir '{}' \; 

Hey. È fantastico! Grazie. Questo ha funzionato quasi interamente. Sto solo avendo un piccolo problema, che sto ricevendo foo1__qux1_bar5.txt, due trattini bassi nel primo livello di cartella. Ho provato a fare casini con la tua linea di base ma nulla sembrava funzionare. Forse devo aggiungere qualcosa?
nunos,

@nunos, non riesco a riprodurre quel comportamento
Glenn Jackman,

Veramente? Strano. Ho appena aggiornato la mia risposta con qualche informazione in più. Potete per favore dare un'occhiata? Grazie.
nunos,

1
eh. OK, cambia "${file//\//_}"in "${file//+(/)/_, e se questa è una sceneggiatura,shopt -s extglob
Glenn Jackman

Ho avuto il problema anche con i due trattini bassi. Sfortunatamente, cambiare il comando come mi hai suggerito non ha funzionato per me. Tuttavia, ho trovato questa risposta su AskDifferent: apple.stackexchange.com/a/254224/122152 Secondo la risposta, macOS potrebbe utilizzare BSD find. Una soluzione alternativa può essere l'uso di findutils. Può essere installato usando homebrew con brew install findutilse poi usando gfindinvece di find. Questo ha funzionato per me.
intagli,

5

Usando la ridenominazione di perl:

find . -depth -type f -exec rename 's@(?<!\.)/@_@g' -- {} \;

PRODUZIONE

$ find -type f
./foo2_bar4 whit a space.txt
./foo3_qux1_bar6.txt
./foo2_bar3.txt
./foo3_qux1_bar5.txt
./foo1_bar2.txt
./foo1_bar1.txt

NOTA

  • Uso uno sguardo negativo (?<!\.) per non toccare il primo./
  • Tengo le directory vuote, mi sento libero di:

    find . -depth -type d -exec rm {} \;

avvertimento Esistono altri strumenti con lo stesso nome che possono o meno essere in grado di farlo, quindi fai attenzione.

Se si esegue il comando seguente ( GNU)

$ file "$(readlink -f "$(type -p rename)")"

e hai un risultato simile

.../rename: Perl script, ASCII text executable

e non contenente:

ELF

allora questo sembra essere lo strumento giusto =)

In caso contrario, per renderlo predefinito (di solito già il caso) Debiane derivato come Ubuntu:

$ sudo update-alternatives --set rename /path/to/rename

(sostituisci /path/to/renameil percorso del tuo perl's renamecomando.


Se non si dispone di questo comando, cercare il gestore pacchetti per installarlo o eseguirlo manualmente


Ultimo ma non meno importante, questo strumento è stato originariamente scritto da Larry Wall, il padre del Perl.


... -type d -exec rmdir ...?
JJoao,

Non sembra che la ridenominazione sia disponibile. Come posso ottenerla esattamente ed è normalmente disponibile in un sistema UNIX? Grazie.
nunos,

@nunos È uno script Perl. È disponibile con il nome perl-renamein Arch Linux e prenamenei sistemi basati su Debian.
Muru,

Aggiunte renamespiegazioni
Gilles Quenot

1

con pax...

pax -Xrwls '|/|_|g' */ "$PWD"

Ciò creerà un collegamento reale nella directory corrente a tutti i file nelle sue directory figlio con un _sostituto per /. È quindi possibile ispezionare i risultati e rimuovere tutte le directory figlio con ...

rm -rf */

... dopo aver verificato i risultati sono di tuo gradimento.


0

Puoi provare con il comando seguente.

$ find -type f -exec bash -c 'mv $0 $(echo $0|sed "s/\//_/2")' {} \;

Il comando sopra sposterà i file e rimarrà la directory che può essere rimossa in seguito.

$ ls
foo1_bar1.txt  foo1_bar2.txt  foo2_bar3.txt  foo2_bar4.txt  foo3_bar5.txt  foo3_bar6.txt
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.