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ą.
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ą.
Odpowiedzi:
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.
new_file/\/thumb?
${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.
/home/user/temps, co nie wynika jasno z pytania. Jeśli nie są, musisz znaleźć lub **.
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.
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.
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.
mv -i ./A A/thumb.png ../tmp/.png- wszystkie pliki kończą się na ../tmp/.png (../tmp to mój katalog docelowy).
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.
read dirwykonuje dzielenie słów i pobiera z katalogu a\nbaib jako dwie instancje, których maskowanie nie może rozwiązać.
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