2012-09-25 10 views
6

Próbuję skopiować wszystkie pliki z jednego katalogu do drugiego, usuwając jednocześnie wszystkie rozszerzenia plików.Jak używać funkcji Znajdź w celu kopiowania i usuwania rozszerzeń zachowujących tę samą strukturę podkatalogów?

From directory 0001: 
0001/a/1.jpg 
0001/b/2.txt 

To directory 0002: 
0002/a/1 
0002/b/2 

Próbowałem już znaleźć ... | xargs c ... p bez powodzenia.

+0

jakie powinno być zachowanie, jeśli istnieją dwa pliki (na przykład 1.txt i 1.jpg) w tym samym katalogu, które mają taką samą nazwę oprócz rozszerzenia? –

+0

wszystkie nazwy plików są poprzedzone unikalnym identyfikatorem, więc nie ma ryzyka nazwania kolizji. – user1345178

Odpowiedz

4

Kopie rekurencyjne są naprawdę łatwe dzięki tar. W twoim przypadku:

tar -C 0001 -cf - --transform 's/\(.\+\)\.[^.]\+$/\1/' . | 
tar -C 0002 -xf - 
+0

+1 - powinieneś zmienić wyrażenie: uniwersalnie usuwając wszelkie rozszerzenia, nie tylko jpg (OP proszą) - ale w przeciwnym razie, fajne rozwiązanie. – kobame

+1

to nowe wyrażenie jest prawie w porządku, ale co zrobi to na przykład z nazwą pliku ".profile"? – kobame

+0

Dobre rozwiązanie. Przetestowano za pomocą 260000 plików (4 godziny). – user1345178

0

wymyśliłem tego brzydkiego kaczątka:

find 0001 -type d | sed 's/^0001/0002/g' | xargs mkdir 
find 0001 -type f | sed 's/^0001//g' | awk -F '.' '{printf "cp -p 0001%s 0002%s\n", $0, $1}' | sh 

Pierwsza linia tworzy drzewo katalogów, a druga linia kopie plików. Problemy z tym są:

  1. Tam jest obsługa tylko dla zwykłych plików i katalogów (nie dowiązania symboliczne etc.)
  2. Jeśli są jakieś okresy (oprócz przedłużenia ) lub znaki specjalne (spacje, itp) w nazwach plików to drugie polecenie nie będzie działać.
2

Jeśli nie masz tar z --transform Może to prace:

TRG=/target/some/where 
SRC=/my/source/dir 
cd "$SRC" 
find . -type f -name \*.\* -printf "mkdir -p '$TRG/%h' && cp '%p' '$TRG/%p'\n" |\ 
    sed 's:/\.::;s:/./:/:' |\ 
    xargs -I% sh -c "%" 

Brak spacji po \ potrzebują prostego końca linii, czy można dołączyć go do jednej linii jak:

find . -type f -name \*.\* -printf "mkdir -p '$TRG/%h' && cp '%p' '$TRG/%p'\n" | sed 's:/\.::;s:/./:/:' | xargs -I% sh -c "%" 

Objaśnienie:

  • find znajdzie wszystkie zwykłe pliki co mają rozszerzenia w was SRC (źródło) katalog
  • Znalezisko za printf przygotuje potrzebne poleceń powłoki:
    • polecenia do tworzenia potrzebnego drzewa katalogów w TRG (target reż)
    • polecenie kopiowania
  • z sed jakiejś kosmetycznej czyszczenia ścieżki (jak sprostowanie /some/path/./other/dir)
  • xargs zajmie całą linię
  • i wykonać przygotowane poleceń z powłoką

Ale to będzie dużo lepiej:

  • prostu dokonać dokładnie kopię w 1 kroku
  • zmiana nazwy plików w drugim kroku

łatwiejsze, czystsze i SZYBCIEJ (nie potrzeba c hecking/tworzenie docelowych podkatalogów)!

+0

Interesuje mnie podejście 2-etapowe, ponieważ katalog zawiera około 1000000 plików. więc SZYBCIEJ jest królem. – user1345178

+0

Pliki Milion? tak więc w tym przypadku (IMO) najlepszym rozwiązaniem są dwie smołowane lany. Jeśli nie masz programu tar z --transform, pobierz go i skompiluj. To na pewno będzie szybsze niż uruchamianie milionów poleceń cp. – jm666

1

Oto niektóre find + bash + zainstalować że załatwi:

for src in `find 0001 -type f` # for all files in 0001... 
do 
    dst=${src/#0001/0002}   # match and change beginning of string 
    dst=${dst%.*}     # strip extension 
    install -D $src $dst   # copy to dst, creating directories as necessary 
done 

Spowoduje to zmianę trybu uprawnień dla wszystkich skopiowanych plików rwxr-xr-x domyślnie zmienna z --mode opcją instalacji jest.

+0

+1 za to, miałem zamiar napisać taką odpowiedź. Najbardziej elegancki tutaj i właściwe narzędzie :) – Zlatko