Jak kopiować i zmieniać nazwy plików znalezionych w Linuksie „znaleźć”?

17

Mam folder o nazwie, /home/user/tempsktóry ma 487 folderów. W każdym folderze mam plik o nazwie thumb.png.

Chcę skopiować wszystkie pliki o nazwie thumb.png do osobnego folderu i zmienić ich nazwę na podstawie folderu, z którego pochodzą.

Miraż
źródło
zmień ich nazwy, jak? Jeśli zastąpisz ogranicznik katalogu czymś - powiedzmy podkreślenie (_), możesz uzyskać kolizje z plikami, które już zawierają podkreślenie. Dotyczy to każdego ważnego znaku, a obok / i \ 0, które są zabronione w nazwach plików, nie ma bezpiecznej przystani - każda postać może spowodować kolizję.
użytkownik nieznany
Czy foldery mają podfoldery, czy tylko zwykłą, szeroką strukturę folderów?
użytkownik nieznany

Odpowiedzi:

8

Proszę bardzo:

for file in /home/user/temps/*/thumb.png; do new_file=${file/temps/new_folder}; cp "$file" "${new_file/\/thumb/}"; done;

edytować:

nawiasem mówiąc, kanoniczna mądrość jest taka, że ​​używanie finddo tego jest złym pomysłem - samo użycie rozszerzenia powłoki jest o wiele bardziej niezawodne. Też to zakłada bash, ale uważam, że to bezpieczne założenie :)

edycja 2:

dla jasności, podzielę to:

# shell-expansion to loop specified files
for file in /home/user/temps/*/thumb.png; do

    # replace 'temps' with 'new_folder' in the path
    # '/home/temps/abc/thumb.png' becomes '/home/new_folder/abc/thumb.png'
    new_file=${file/temps/new_folder};

    # drop '/thumb' from the path
    # '/home/new_folder/abc/thumb.png' becomes '/home/new_folder/abc.png'
    cp "$file" "${new_file/\/thumb/}";
done;

szczegółowe informacje na temat ${var/Pattern/Replacement}konstrukcji można znaleźć tutaj .

cudzysłowy w cpwierszu są ważne do obsługi spacji i znaków nowej linii itp. w nazwach plików.

Szymon
źródło
nowy_plik = nowy_folder? Jaki jest cel odwrotnego ukośnika przed ukośnikiem new_file/\/thumb?
użytkownik nieznany
1
@ użytkownik: ${VARIABLE/PATTTERN/REPLACEMENT}tworzy wartość, VARIABLEale wzór zastępuje tekstem zastępczym. Tutaj jest wzór /thumb( /należy go usunąć, aby nie wyglądał ${new_file//PATTERN/REPLACEMENT}, co czyni go globalnym zamiennikiem zamiast zastąpienia za pierwszym razem), a tekst zastępczy jest pusty.
Gilles „SO- przestań być zły”
Oczywiście teraz to widzę. :)
użytkownik nieznany
1
Zakładasz, że 487 katalogów znajduje się bezpośrednio pod /home/user/temps, co nie wynika jasno z pytania. Jeśli nie są, musisz znaleźć lub **.
Gilles 'SO - przestań być zły'
@Gilles - Naprawdę tak właśnie czytam pytanie. Doceń ten punkt :)
simon
5

Działa to w przypadku dowolnie głębokich podkatalogów:

$ find temps/ -name "thumb.png" | while IFS= read -r NAME; do cp -v "$NAME" "separate/${NAME//\//_}"; done
`temps/thumb.png' -> `separate/temps_thumb.png'
`temps/dir3/thumb.png' -> `separate/temps_dir3_thumb.png'
`temps/dir3/dir31/thumb.png' -> `separate/temps_dir3_dir31_thumb.png'
`temps/dir3/dir32/thumb.png' -> `separate/temps_dir3_dir32_thumb.png'
`temps/dir1/thumb.png' -> `separate/temps_dir1_thumb.png'
`temps/dir2/thumb.png' -> `separate/temps_dir2_thumb.png'
`temps/dir2/dir21/thumb.png' -> `separate/temps_dir2_dir21_thumb.png'

Interesującą częścią jest rozszerzenie parametru ${NAME//\//_} . Zajmuje treści NAMEi zastępuje każde wystąpienie /z _.

Uwaga: wynik zależy od katalogu roboczego i parametru ścieżki do znalezienia. Wykonałem polecenie z katalogu nadrzędnego temps. Wymień cpsię echodo eksperymentu.

lesmana
źródło
Nie działa w przypadku plików, które zawierają nową linię w nazwie.
użytkownik nieznany
Cóż, to działało bardzo dobrze. jeszcze jedno: mam też kilka plików zip w niektórych podkatalogach. czy możliwe jest również wydobycie stamtąd obrazów? pamiętaj „zip not tar”
Mirage
1

Krótki kod pomocnika:

#!/bin/bash
#
# echo cp "$1" ../tmp/"${1//\//_}" 
#
mv "$1" ../tmp/"${1//\//_}"

nazwijmy go „deslash.sh” i uczyńmy go wykonywalnym. Zadzwoń za pomocą:

find -type f -name thumb.png -exec ./deslash.sh {} ";"    

Nie powiedzie się, jeśli istnieje kolizja

a/b/thumb.png # and 
a_b/thumb.png 

ale to nieuniknione.

nieznany użytkownik
źródło
0

Spróbuj tego

mkdir /home/user/thumbs
targDir=/home/user/thumbs

cd /home/user/temps

find . -type d | 
 while IFS="" read -r dir ; do
   if [[ -f "${dir}"/thumb.png ]] ; then
     echo mv -i "${dir}/thumb.png" "${targDir}/${dir}_thumb.png"
   fi
done

Edytować

Dodałem cytowanie na wypadek, gdyby któreś z twoich nazw reżimów zawierało znaki spacji.

Zmieniłem to również, aby wyświetlało tylko polecenia do wykonania. Sprawdź dane wyjściowe skryptu, aby upewnić się, że wszystkie nazwy plików / ścieżek wyglądają poprawnie. Jeśli jesteś pewien, że nie ma żadnych problemów z poleceniami, które zostaną wykonane, usuń echo.

łobuz
źródło
Mam trochę plików png w kilku podfolderach, czy to zadziała
Mirage,
dla mojego folderu „A A” tworzy: mv -i ./A A/thumb.png ../tmp/.png- wszystkie pliki kończą się na ../tmp/.png (../tmp to mój katalog docelowy).
użytkownik nieznany
Dodaj cudzysłowy i nawiasy klamrowe wokół wszystkich zmiennych w powyższym kodzie, tj. „$ {Dir}”
shellter
@ Mirror51 napisał: „Pliki w kolejnych podfolderach będą działać”. Tak, powinno. Czy wiesz, że możesz wykonać każdy krok tego skryptu osobno (lub po połączeniu, każdy zestaw potoków). Możesz wykonać tylko find -type di zobaczyć wynik. Czy otrzymujesz wszystkie katalogi, których oczekujesz? Jeśli nie, należy dodać dane wyjściowe, aby pokazać problem. Powodzenia.
shellter
Nie zadziała read dirwykonuje dzielenie słów i pobiera z katalogu a\nbaib jako dwie instancje, których maskowanie nie może rozwiązać.
użytkownik nieznany
-1

Aby skopiować, potrzebujesz polecenia cp , a zmiana nazwy dla Linuksa jest taka sama jak przeniesienie pliku, więc musisz to zrobić za pomocą polecenia mv . W Linuksie zawsze musisz podać całą ścieżkę, od źródła, jeśli jesteś w innym folderze, i oczywiście do folderu docelowego. Byłbym coś takiego, dla kopii:

cp /source_path/file /destination_path/

lub zmienić nazwę lub przenieść

mv /source_path/old_file /destination_path/new_name_file

źródło
To tylko niewielka część pytania plakatu. Teraz wyjaśnij, jak iterować po katalogach i kopiować miniatury :-)
OP chce użyćfind
Tak, masz rację ... Nie wiem, co się ze mną stało ...