it-swarm-eu.dev

Sloučení vnořeného adresáře

To je pravděpodobně velmi jednoduché, ale nedokážu to přijít. Mám strukturu adresářů jako je tato (dir2 je uvnitř dir1):

/dir1
    /dir2 
       |
        --- file1
       |
        --- file2

Jaký je nejlepší způsob, jak 'zploštit' tuto strukturu režiséra takovým způsobem, jak získat file1 a file2 v dir1, ne dir2.

78
turtle

Můžete to provést pomocí GNU find a GNU mv:

find /dir1 -mindepth 2 -type f -exec mv -t /dir1 -i '{}' +

V podstatě způsob, jak funguje, pokud tento find prochází celým stromem adresářů a pro každý soubor (-type f), Který není v adresáři nejvyšší úrovně (-mindepth 2), spustí mv a přesune jej do požadovaného adresáře (-exec mv … +). Argument -t Na mv umožňuje určit cílový adresář jako první, což je nutné, protože forma +-exec Umístí všechna zdrojová umístění na konec příkazu. -i Způsobí, že se mv zeptá, než přepíše duplikáty; můžete nahradit -f a přepsat je bez požadavku (nebo -n, abyste se neptali ani nepřepisovali).

Jak zdůrazňuje Stephane Chazelas, výše uvedené funguje pouze s nástroji GNU (které jsou standardní pro Linux, ale ne většina ostatních systémů)) Následující je poněkud pomalejší (protože vyvolává mv vícekrát), ale mnohem univerzálnější:

find /dir1 -mindepth 2 -type f -exec mv -i '{}' /dir1 ';'
79
derobert

V zsh:

mv dir1/*/**/*(.D) dir1

**/ Rekurzivně prochází podadresáře. kvalifikátor glob. Odpovídá pouze běžným souborům a D zajišťuje zahrnutí tečkových souborů (ve výchozím nastavení jsou soubory, jejichž název začíná na .) jsou vyloučeny ze zástupných zápasů). Chcete-li později vyčistit nyní prázdné adresáře, spusťte rmdir dir1/**/*(/Dod) - / Omezuje se na adresáře a od nejprve objedná hloubku zápasu, aby se odstranil dir1/dir2/dir3 před dir1/dir2.

Pokud je celková délka názvů souborů velmi velká, můžete narazit na omezení délky příkazového řádku. Zsh má vestavěné funkce pro mv a rmdir, na které se toto omezení nevztahuje: spusťte zmodload zsh/files A povolte je.

Pouze nástroje POSIX:

find dir1 -type f -exec mv {} dir1 \;
find dir1 -depth -exec rmdir {} \;

nebo (rychlejší, protože nemusí spouštět samostatný proces pro každý soubor)

find dir1 -type f -exec sh -c 'mv "[email protected]" dir1' _ {} +
find dir1 -depth -exec rmdir {} +

tar a zip mají schopnost začlenit a poté odstranit adresářovou strukturu, takže jsem mohl rychle vyrovnat vnořený adresář pomocí

tar -cvf all.tar *

následuje přesunutí all.tar na nové místo

tar -xvf all.tar --strip=4

3
John

Zkuste to udělat:

cp /dir1/dir2/file{1,2} /another/place

nebo pro každý soubor odpovídající file[0-9]* v subdir:

cp /dir1/dir2/file[0-9]* /another/place

Viz http://mywiki.wooledge.org/glob

3
Gilles Quenot

Napsal jsem dvě funkce, které můžete použít společně a které jen dělají, můžete omezit úroveň adresáře přidáním -maxdepth $VAL parametr.

# This scripts flattens the file directory
# Run this script with a folder as parameter:
# $ path/to/script path/to/folder

#!/bin/bash

rmEmptyDirs(){
    local DIR="$1"
    for dir in "$DIR"/*/
    do
        [ -d "${dir}" ] || continue # if not a directory, skip
        dir=${dir%*/}
        if [ "$(ls -A "$dir")" ]; then
            rmEmptyDirs "$dir"
        else
            rmdir "$dir"
        fi
    done
    if [ "$(ls -A "$DIR")" ]; then
        rmEmptyDirs "$DIR"
    fi
}

flattenDir(){
    local DIR="$1"
    find "$DIR" -mindepth 2 -type f -exec mv -i '{}' "$DIR" ';'
}

read -p "Do you wish to flatten folder: ${1}? " -n 1 -r
echo    # (optional) move to a new line
if [[ $REPLY =~ ^[Yy]$ ]]
then
    flattenDir "$1" &
    rmEmptyDirs "$1" &
    echo "Done";
fi
2
Bruno

Rozšiřuji populární odpověď na tuto otázku, protože jsem měl případ použití pro sloučení adresáře obsahujícího soubory se stejným názvem.

dir1/
├── dir2
│   └── file
└── dir3
    └── file

V tomto případě -i (--interactive) možnost předaná uživateli mv by nepřinesla požadovaný výsledek ke sloučení struktury adresářů a ke konfliktům názvů. Takže je to jednoduše nahrazeno --backup=t (ekvivalentní --backup=numbered). Další dokumentace k -b (--backup) možnost dostupná na https://www.gnu.org/software/coreutils/manual/coreutils.html#Backup-options .

Což má za následek:

find dir1/ -mindepth 2 -type f -exec mv -t dir1/ --backup=t '{}' +

Což přináší:

dir1/
├── dir2
├── dir3
├── file
└── file.~1~
1
Yann Eves