İç içe bir dizini düzleştirme


Yanıtlar:


75

Bunu GNU findve GNU ile yapabilirsiniz mv:

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

Temel olarak, eğer bu işlem findtüm dizin ağacından geçiyorsa -type fve üst düzey dizinde ( -mindepth 2) mvbulunmayan her dosya ( ) için geçerliyse, a'yı istediğiniz dizine taşımak için çalışır ( -exec mv … +). Öncelikle hedef dizini belirlemenizi sağlayan -targümandır mv, çünkü +form -exectüm kaynak konumlarını komutun sonuna koyar. Makale -i, mvkopyaların üzerine yazmadan önce sorar; -fsormadan onları üzerine yazmak yerine (veya -nsormamak veya üzerine yazmak yerine) kullanabilirsiniz.

Stephane Chazelas'ın işaret ettiği gibi, yukarıdakiler yalnızca GNU araçlarıyla çalışır (Linux'ta standarttır, ancak çoğu diğer sistemlerde yoktur). Aşağıdakiler biraz daha yavaştır (çünkü mvbirkaç kez çağırır ) ancak çok daha evrenseldir:

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

3
-exec +Çok sayıda işlem gerçekleştirmeyecek şekilde kullanımı düzenlendimv
Random832

1
@ Random832 Ve tekrar geri dönecek çünkü + çalışmıyor. mvHedefe son argüman olarak ihtiyaç duyuyor, fakat + kaynakları son argüman olarak kullanıyor. Değiştirdiğiniz sözdizimini bile kabul etmeyeceksiniz ( find: missing argument to `-exec')
derobert

1
@ Random832 ama sanırım kullanabileceğimiz mvbir -tşey var, o yüzden bunu değiştireceğim.
derobert

1
@Dom, findgizli (nokta) dosyaları varsayılan olarak yazdırır. Derinlik, bulmak için ilettiğiniz dizine göredir.
derobert

1
Ya find ./dir -mindepth 2 -type f -exec mv -f '{}' ./dir ';'da yinelenen kopyaları geçersiz kılma durumunda
Atav32

33

Zsh içinde:

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

**/alt dizinleri yinelemeli olarak geçirir. Glob eleme . sadece normal dosyaları eşleşir ve D(varsayılan, adını başlayan bir dosyalar tarafından dot dosyaları dahil edilmesini sağlar .joker dışında tutulmuştur maçları). Artık boş olan dizinleri daha sonra temizlemek için, run rmdir dir1/**/*(/Dod)- /dizinleri kısıtlar ve daha önce odkaldırmak üzere dir1/dir2/dir3önce eşleşme derinliğini emreder dir1/dir2.

Dosya adlarının toplam uzunluğu çok büyükse, komut satırı uzunluğunda bir sınırlama olabilir. Zsh, bu sınırlamadan etkilenmeyen mvve rmdiretkilenmeyen yapılara sahiptir: zmodload zsh/filesbunları etkinleştirmek için çalıştırın .

Sadece POSIX araçlarıyla:

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

veya (daha hızlı çünkü her dosya için ayrı bir işlem yürütmek zorunda değildir)

find dir1 -type f -exec sh -c 'mv "$@" dir1' _ {} +
find dir1 -depth -exec rmdir {} +

1
Bu kabul edilen cevap olmalı! Özellikle özlü zsh sürümü ile.
Adamski


2

Sadece bunu birlikte kullanabileceğiniz iki fonksiyon yazdım, bir -maxdepth $VALparametre ekleyerek dizin seviyesini sınırlandırabilirsiniz .

# 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

Dostum, sadece beynimi, sunucumu mahvetti, yol argümanını unutarak yanlış kullandım. Tamam, yapıştırma
işlerini

Tüh! Bunu duyduğuma üzüldüm. Umarım bir yedeğin vardır ... Gelecekteki koruma için bir onay ekledim.
Bruno,

Thanks @Bruno bu şekilde daha iyi. Sunucum hala sorunsuz çalışıyor, sadece betiği çalıştırmayı durduran bir hata görene kadar, boş dizinleri yinelemeli (ve bu benim hatamdı) kökünden silmek için "düzleştir" kısmını yorumladım.
Dulgan

1

Aynı isimdeki dosyaları içeren bir dizini düzleştirmek için bir kullanım davası aldığım için bu sorunun popüler cevabını genişletiyorum.

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

Bu durumda, -i( --interactive) seçeneği mv, dizin yapısını düzleştirmek ve ad çakışmalarını işlemek için istenen sonucu vermez. Bu yüzden basitçe --backup=t(eşdeğer --backup=numbered) ile değiştirilir . Https://www.gnu.org/software/coreutils/manual/coreutils.html#Backup-options adresinde bulunan -b( --backup) seçeneğiyle ilgili daha fazla belge .

Sonuçlanan:

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

Hangi verim:

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

1

katran ve fermuarın her ikisi de bir dizin yapısını dahil etme ve daha sonra sıyırma becerisine sahip olduğundan, iç içe geçmiş bir dizini hızlı bir şekilde düzleştirebildim.

tar -cvf all.tar *

ardından all.tar öğesini yeni bir yere taşıdıktan sonra

tar -xvf all.tar --strip=4

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.