Jak kopiować lub przenosić pliki -n poziomy wyżej na OSX przez powłokę

2

Jak mogę znaleźć wszystkie pliki określonego typu / nazwy i skopiować je o -n poziom wyżej ? Oto struktura drzewa systemu plików:

germany/
       |
       adventure/
                |
                300x600/
                |      |
                |      file1.jpg
                |      file2.zip
                |
                400x600/
                       |
                       file8.jpg
                       file4.zip
switzerland/
           |
           adventure/...

Istnieje wiele folderów krajowych, około 20, a pliki .zip nie mają gwarancji głębokości 3 poziomów. Obecnie jestem w ich folderze nadrzędnym countries/i chcę znaleźć i skopiować wszystkie pliki .zip w górę o jeden poziom, do adventure/katalogu odpowiedniego kraju / folderu.

Próbowałem:

find . -type f -name '*.zip' -exec mv {}/.. \;

ale ten nieszczęśliwie zawiódł. Przesuwało każdy plik o jeden poziom wyżej, a następnie były przenoszone jeszcze raz o jeden poziom wyżej.

Dzięki!

EDYCJA: Grałem trochę z rozwiązaniami z odpowiedzi i czytałem dużo manstron :). Wreszcie zaakceptowałem rozwiązanie, które najbardziej mi się podobało, ponieważ jest eleganckie i niezależne od powłoki.

Nadal próbuję coś wymyślić:

  1. Czy finddziała jako pętla lub czy nawiasy klamrowe są traktowane jako „lista / tablica” w innych językach programowania? Czyli: czy wypełnia się znalezionymi wynikami (tzn. Ciągami) naraz, a następnie przekazuje się polecenie poniżej -exec?
  2. Dlaczego przeniesienie miało miejsce najpierw o jeden poziom wyżej, a następnie o jeden poziom wyżej?
  3. Czy istnieje sposób, aby od razu powiedzieć, mv/cpaby przejść -n poziomy [góra / dół]?
Alex Starbuck
źródło

Odpowiedzi:

0

Możesz uczynić go niezależnym od powłoki i skondensować w jedno findpolecenie:

find . -type f -name '*.zip' -exec \
sh -c 'echo cp -- "$0" "$(dirname "$0")"/..' {} \;

Usuń, echogdy masz pewność, że robi to, co chcesz.

Użyj finddo zlokalizowania plików. Wykonaj powłokę za pomocą -exec sh -c, przekazując znaleziony plik {}jako pierwszy argument do tej powłoki. Dlatego powłoka będzie miała dostęp do ścieżki pliku jako $0.

Następnie można użyć dirname "$0"oraz substytucji polecenia ( $(…)), aby uzyskać katalog nadrzędny pliku. Dołącz tyle, /..ile chcesz przejść wyżej.

Zauważ, że zacytowałem nazwy plików, aby zapobiec nieprawidłowemu rozwinięciu plików z nowymi liniami lub spacjami w nazwie.

slhck
źródło
Uwaga dodatkowa: W swoim pytaniu mówisz, że chcesz „skopiować”, ale później używasz mvpolecenia. Zakładam, że chcesz skopiować pliki, jak mówią tytuł i wprowadzenie.
slhck,
Rozumiem! mvlub cpnie ma znaczenia, mogę używać i obsługiwać oba :) Tak więc findznajduje ścieżki do plików .zip, wypełnia {}„obiekt” wynikami. -execwykonuje się sh -cz opcją „read from string” (-c), która „definiuje” (?) dwa argumenty - pierwszy argument będzie pierwszy path/to/file.zipz wyników {}. Następnie wyodrębnij katalog-rodzic-plik-pliku, w końcu przejdź na wyższy poziom i cpplik. Poprawny?
Alex Starbuck,
Tak, właściwie to się tutaj dzieje! W shtym przypadku wywołanie ma dwie -c "cmd"opcje argumentów, jedna to (= „weź polecenia do wykonania z ciągu, który następuje”), a druga to {}, jak to słusznie mówisz, ścieżka do pierwszego znalezionego pliku, następnie w drugiej pętli drugi plik itp. -exec sh -c "…"Podejście to jest bardzo przydatne w przypadku bardziej złożonych findskryptów, dla których w innym przypadku musiałbyś napisać kilka pętli.
slhck,
Czy mógłbyś rozwinąć nieco więcej - jestem zdezorientowany co do łańcucha. Istnieje polecenie (cp), a po nim dwie zmienne ($ 0 i $ (...)). Jak to działa wewnętrznie? W jaki sposób pełna ścieżka / do / pliku kończy się na 0 USD, a następnie do tego jest stosowane inne polecenie dirname? Vielen dank!
Alex Starbuck,
$0to pierwszy argument przekazany do sh -c '…'. Możesz uruchomić, sh -c 'echo $0 $1 $2' foo bar baz a dostaniesz foo bar bazjako wynik. W twoim przypadku pierwszym argumentem był {}który findzastępuje ze ścieżką do znalezionego pliku. Tak więc pierwszym argumentem cpjest ścieżka do pliku. Drugi argument musi być folderem nadrzędnym pliku, więc najpierw musimy uzyskać nazwę folderu…
slhck
0

wypróbowałem to z Ubuntu Zsh 5.0.2:

for pdir in */
do
  cd $pdir
  for dir in */
  do
    cd $dir
    mv */*.zip .
    cd ..
  done
  cd ..
done
Phillip -Zyan K Lee- Stockmann
źródło
Blisko. Chcę mieć wszystkie pliki .zip dwa poziomy wyżej, co oznacza w adventure/podkatalogu germany/katalogu. Istnieją też inne katalogi nazwane według nazw krajów, więc chciałbym móc wydać polecenie dla wszystkich (np. Austria / Niemcy / ...). Dzięki
Alex Starbuck,
ok - pozwól, że spróbuję jeszcze raz - ale znowu, nie ma zsh, żeby to zweryfikować ;-)
Phillip -Zyan K Lee- Stockmann
Próbowałem tego w kontenerze ubuntu lxc i zsh 5.0.2. Powinien działać jak urok ;-)
Phillip -Zyan K Lee- Stockmann
To powinno działać, ale tylko dla jednego katalogu na poziomie głównym (np. germany), Nie dla wszystkich.
slhck,
a teraz? :-D
Phillip -Zyan K Lee- Stockmann
0

Tylko szybka alternatywa, jeśli rzeczywistość jest tak prosta, jak podany przykład:

cd germany
mv */*/*.zip .

(i nie ma zillion plików)

Matija Nalis
źródło
Jak wspomniano w komentarzu powyżej, OP chce to zrobić dla każdego folderu, nie tylko germany. Potrzebujesz pętli nad wszystkimi folderami.
slhck,
Tak, muszę to zrobić dla wszystkich folderów „country”, a nie tylko jednego i nie jestem pewien, czy pliki .zip zawsze będą miały trzy poziomy głębokości. W każdym razie dzięki;)
Alex Starbuck,