Podany poniżej skrypt umieszcza „podkreślenie” zamiast „białych znaków” we wszystkich nazwach plików w określonym folderze. Mam problem z tworzeniem skryptu powłoki, który umieszcza „podkreślenie” zamiast „białych znaków” w nazwach wszystkich podfolderów i zawartych w nich plików, a nie tylko w folderze.
Czy ktoś ma jakieś wskazówki, jak to zrobić?
Oto mój kod:
#!/bin/bash
ls | while read -r FILE; do
mv -v "$FILE" `echo $FILE | tr ' ' '_'`
done
bash
shell
shell-script
Rafael
źródło
źródło
find
do swojejwhile
pętli zamiastls
. Najbezpieczniej byłoby przeczytać instrukcję i użyć opcji takich jak-maxdepth
. Możesz także spojrzeć na-exec
opcję całkowitego uniknięcia pętli.Odpowiedzi:
Użyj find do wyszukiwania w katalogach i podkatalogach:
find "$(pwd)" -type f -print0
- Drukuje wszystkie znalezione ścieżki do plików w bieżącym katalogu i podkatalogach.Dzięki procesowi podstawienia wyjście polecenia find jest wysyłane do pętli while, gdzie odczytuje zmienną fname.
nname="${fname##*/}"
- Wyodrębnia nazwę pliku ze ścieżki"${fname%/*}"
- wyodrębnia ścieżkę"${nname//[[:space:]]/"_"}"
- zamienia spacje w nazwie pliku na _"${fname%/*}/${nname//[[:space:]]/"_"}"
- ścieżka / nowa_nazwa_plikuźródło
$(pwd)
w przypadku, gdy zawiera spacje (lub po prostu użyć.
zamiast) i dodać-name "* *"
dofind
polecenia, aby pominąć pliki, które nie mają miejsca i dodać albo-i
czy-n
domv
komendy, aby uniknąć utraty danych, jeśli istnieje konflikt nazwy pliku.Zamiast tego użyj
rename
narzędzia , npAby zmienić nazwę rekurencyjną, spróbuj:
gdzie
**
jest opcja globowania Bash (włącz przezshopt -s globstar
).Alternatywnie użyj
find
npźródło
W
bash
(nie jestem pewien co do pochodnych ish
!) Możesz używać podstawiania zmiennych itp. W zmiennychJEDNAK TO co najmniej nie zajmuje się innymi znakami spacji (tab itp.)
źródło
Moje podejście:
Wersja wieloliniowa dla czytelności:
Wyjaśnienie:
find . -name "* *"
znajduje obiekty, których nazwy należy zmienić. Notatkafind
jest bardzo elastyczna dzięki swoim testom, więc jeśli chcesz (np.) Zmieniać nazwy tylko katalogów, zacznij odfind . -depth -type d -name "* *"
.-execdir
wykonuje podany proces (bash
) w katalogu, w którym znajduje się obiekt, więc każda przekazywana ścieżka{}
jest zawsze taka./bar
, jak nie./foo/bar
. Oznacza to, że nie musimy przejmować się całą ścieżką. Minusem jest to,mv -v
że nie pokazuje ci ścieżki, więc dodałempwd
tylko dla informacji (możesz ją pominąć, jeśli chcesz).bash
pozwala nam użyć"${baz// /_}"
składni.-depth
zapewnia, że nic się nie stanie:find
zmieni nazwę katalogu (jeśli dotyczy), a następnie spróbuje przetworzyć jego zawartość starą ścieżką.{} +
jest w stanie wyżywićbash
się z wielu obiektów (w przeciwieństwie do{} \;
składni). Iterujemy nad nimifor f in "$@"
. Nie chodzi o to, aby uruchamiać osobnybash
proces dla każdego obiektu, ponieważ utworzenie nowego procesu jest kosztowne. Myślę, że nie możemy łatwo uniknąć uruchamiania osobnych opcjimv
; Mimo to zmniejszenie liczbybash
wywołań wydaje się dobrą optymalizacją (pwd
jest wbudowanebash
i nie kosztuje nas procesu). Jednak-execdir ... {} +
nie będą przekazywać plików z różnych katalogów jednocześnie. Używając-exec ... {} +
zamiast,-execdir ... {} +
możemy dodatkowo zmniejszyć liczbę procesów, ale wtedy musimy dbać o ścieżki, a nie tylko nazwy plików (porównaj tę inną odpowiedź , wydaje się, że wykonuje przyzwoitą robotę, alewhile read
spowalnia ją). Jest to kwestia prędkości w porównaniu z (względną) prostotą. Moje rozwiązanie z-exec
jest poniżej.dummy
tuż przed tym{}
staje się$0
w naszymbash
. Potrzebujemy tego fałszywego argumentu, ponieważ"$@"
jest on równoważny"$1" "$2" ...
(nie"$0" "$1" ...
). W ten sposób wszystko, co przeszło,{}
jest dostępne później jako"$@"
.Bardziej złożona, nieco zoptymalizowana wersja (różne
${...}
sztuczki zaczerpnięte z innej odpowiedzi ):Inne podejście (eksperymentalne!) Obejmuje
vidir
. Sztuką sąvidir
zastosowania,$EDITOR
które mogą nie być interaktywnym edytorem :Ostrzeżenia:
s/ /_/g
bezpośrednio,\d32
jest to obejście.vidir
działa, podejście byłoby trudne, jeśli chcesz zastąpić cyfrę lub tabulator.vidir
działa ze ścieżkami, nie tylko nazwami plików (nazwami podstawowymi), dlatego zmiana nazw tylko plików (tj. Nie katalogów) może być trudna.Niemniej jednak, jeśli wiesz, co robisz, może to wykonać pracę jeszcze szybciej. Nie polecam jednak takiego (ab) użycia
vidir
w ogólnym przypadku. Włączyłem to do mojej odpowiedzi, ponieważ uważałem to eksperymentalne podejście za interesujące.źródło