Mam folder o nazwie, /home/user/temps
któ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/temps
któ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 find
do 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 cp
wierszu 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ść, VARIABLE
ale 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 NAME
i 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ń cp
się echo
do 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 d
i zobaczyć wynik. Czy otrzymujesz wszystkie katalogi, których oczekujesz? Jeśli nie, należy dodać dane wyjściowe, aby pokazać problem. Powodzenia.
read dir
wykonuje dzielenie słów i pobiera z katalogu a\nb
aib 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