Mam katalog z wieloma plikami img, a niektóre z nich są identyczne, ale wszystkie mają różne nazwy. Muszę usunąć duplikaty, ale bez narzędzi zewnętrznych tylko ze bash
skryptem. Jestem początkującym w Linuksie. Próbowałem zagnieździć pętlę for, aby porównać md5
sumy i w zależności od wyniku usunąć, ale coś jest nie tak ze składnią i to nie działa. jakaś pomoc?
próbowałem ...
for i in directory_path; do
sum1='find $i -type f -iname "*.jpg" -exec md5sum '{}' \;'
for j in directory_path; do
sum2='find $j -type f -iname "*.jpg" -exec md5sum '{}' \;'
if test $sum1=$sum2 ; then rm $j ; fi
done
done
Dostaję: test: too many arguments
bash
shell-script
linuxbegin
źródło
źródło
Odpowiedzi:
W twoim skrypcie jest sporo problemów.
Po pierwsze, aby przypisać wynik polecenia do zmiennej, musisz ująć ją w backtics (
`command`
) lub, najlepiej, w$(command)
. Masz go w pojedynczych cudzysłowach ('command'
), które zamiast przypisywać wynik polecenia do zmiennej, przypisują samo polecenie jako ciąg znaków. Dlatego twojetest
jest w rzeczywistości:Następnym problemem jest to, że polecenie
md5sum
zwraca więcej niż tylko skrót:Chcesz tylko porównać pierwsze pole, więc powinieneś przeanalizować dane
md5sum
wyjściowe, przekazując je za pomocą polecenia, które wypisuje tylko pierwsze pole:lub
Ponadto
find
polecenie zwróci wiele dopasowań, a nie tylko jedno, a każde z nich zostanie powtórzone przez drugifind
. Oznacza to, że w pewnym momencie będziesz porównywał ten sam plik z samym sobą, suma md5 będzie identyczna i skończysz na usuwaniu wszystkich plików (uruchomiłem to w katalogu testowym zawierającyma.jpg
ib.jpg
):Nie chcesz uruchamiać,
for i in directory_path
chyba że przekazujesz tablicę katalogów. Jeśli wszystkie te pliki znajdują się w tym samym katalogu, chcesz uruchomićfor i in $(find directory_path -iname "*.jpg"
), aby przejrzeć wszystkie pliki.Nie jest dobrym pomysłem stosowanie
for
pętli z wyjściem find. Powinieneś użyćwhile
pętli lub globowania :lub jeśli wszystkie twoje pliki znajdują się w tym samym katalogu:
W zależności od powłoki i ustawionych opcji możesz używać globowania nawet dla plików w podkatalogach, ale nie wchodźmy w to tutaj.
Na koniec powinieneś również podać swoje zmienne, inaczej ścieżki katalogu ze spacjami spowodują uszkodzenie skryptu.
Nazwy plików mogą zawierać spacje, nowe linie, ukośniki odwrotne i inne dziwne znaki, aby poprawnie radzić sobie z nimi w
while
pętli, musisz dodać więcej opcji. To, co chcesz napisać, to:Jeszcze prostszym sposobem byłoby:
Lepsza wersja, która radzi sobie ze spacjami w nazwach plików:
Ten mały skrypt Perla przejdzie przez wyniki
find
polecenia (tj. Md5sum i nazwa pliku).-a
Opcja dlaperl
linii wejściowych dzieli na białych znaków i zapisuje je naF
tablicy, więc$F[0]
będzie md5sum i$F[1]
nazwa pliku. Wartość md5sum jest zapisywana w haszu,k
a skrypt sprawdza, czy hash został już wyświetlony (if $k{$F[0]}>1
), i usuwa plik, jeśli ma (system("rm $F[1]")
).Chociaż to zadziała, będzie bardzo powolne w przypadku dużych kolekcji obrazów i nie można wybrać, które pliki zachować. Istnieje wiele programów, które obsługują to w bardziej elegancki sposób, w tym:
fdupes
fslint
źródło
unlink
zamiast nawiązywaćsystem
połączenia.$F[1]
. Naprawiono to za pomocą wycinków tablicy. Co do unlink (), wiem, ale chciałem ograniczyć perlizmy do minimum, a wywołanie systemowe jest łatwiejsze do zrozumienia, jeśli nie znasz Perla.Istnieje sprytny program o nazwie,
fdupes
który upraszcza cały proces i monituje użytkownika o usunięcie duplikatów. Myślę, że warto sprawdzić:Zasadniczo podpowiedział mi, który plik zachować , wpisałem 1 i usunąłem drugi.
Inne interesujące opcje to:
Z twojego przykładu prawdopodobnie chcesz uruchomić go jako:
Zobacz
man fdupes
wszystkie dostępne opcje.źródło