Mój problem (w skrypcie z #!/bin/sh
) wygląda następująco: Próbuję zsumować wszystkie pliki w katalogu do celów archiwalnych. Plik sumy kontrolnej (w moim przypadku sha1) ze wszystkimi nazwami plików powinien znajdować się w tym samym katalogu. Powiedzmy, że mamy katalog ~/test
z plikami f1
i f2
:.
mkdir ~/test
cd ~/test
echo "hello" > f1
echo "world" > f2
Teraz obliczamy sumy kontrolne za pomocą
find -maxdepth 1 -type f -printf '%P\n' | xargs shasum
robi dokładnie to, co chcę, wyświetla listę wszystkich plików bieżącego katalogu i oblicza sumy sha1 (maxdepth można zmienić później). Dane wyjściowe STDOUT to:
f572d396fae9206628714fb2ce00f72e94f2258f f1
9591818c07e900db7e1e0bc4b884c945e6a61b24 f2
Niestety przy próbie zapisania tego pliku do pliku
find -maxdepth 1 -type f -printf '%P\n' | xargs shasum > sums.sha1
plik wynikowy wyświetla sumę kontrolną dla siebie:
da39a3ee5e6b4b0d3255bfef95601890afd80709 sums.sha1
f572d396fae9206628714fb2ce00f72e94f2258f f1
9591818c07e900db7e1e0bc4b884c945e6a61b24 f2
i dlatego nie powiedzie się później shasum --check
, z powodu oczywistego problemu dodatkowej modyfikacji pliku podczas zapisywania ostatniej sumy.
Rozejrzałem się i używając -p
flagi dla xargs
, dowiedziałem się, że jakoś tworzy plik wyjściowy przed wykonaniem polecenia find, dlatego dodatkowy plik zostanie znaleziony i zostanie sprawdzony ...
Wiem, że jako obejście problemu mogłem zapisać sumę kontrolną w innej lokalizacji (katalog tymczasowy przez mktemp
) lub wykluczyć ją w znalezieniu, ale chciałbym zrozumieć, dlaczego zachowuje się tak, jak to działa - co w moich oczach nie jest takie przydatne, na przykład, jeśli pierwsze polecenie sprawdzi, czy plik wyjściowy jest już na dysku, nigdy nie uzyska poprawnej odpowiedzi ...
xargs
, to sama powłoka tworzy ten plik, ponieważ przed wykonaniem jakiegokolwiek polecenia najpierw przekierowuje wszystkie dane wejściowe, wyjściowe i potoki, tak że pofind
uruchomieniu plik wyjściowy już istnieje.-exec
Zamiast tego użyj :find -maxdepth 1 -type f -exec sh -c 'shasum "$@" > sums.sha1' {} +
sh
konieczne jest kilka inwokacji. Zauważ, że potrzebujesz argumentu$0
wcześniej{}
.tee
zniknęła? Próbowałem i działa dobrze, tłumiłem również STDOUT dodając1>/dev/null
. Czy było coś nie tak z odpowiedzią, czy błąd?Odpowiedzi:
Możesz uniemożliwić dostęp do pliku
xargs
za pomocą:Aby zapobiec problemom z nazwami plików, które mają spacje lub znaki nowej linii, cytaty lub ukośniki odwrotne, użyłbym jednak:
zamiast.
Ma
--
to na celu uniknięcie problemów z nazwami plików rozpoczynającymi się od-
. Nie pomoże to jednak w przypadku pliku o nazwie-
. Gdybyś używał-print0
zamiast tego-printf '%P\0'
, nie byłbyś potrzebny--
i nie miałby problemu z-
plikiem.źródło
basename
uzyskiwałem nazwę pliku sums.sha1 z podanej pełnej ścieżki (nie zostało to uwzględnione w pytaniu, ale może pomóc innym).Ponieważ używasz
-maxdepth 1
, zakładam, że nie chcesz rekurencji. Jeśli tak, po prostu zrób to w powłoce:Aby pominąć katalogi, możesz:
Jeśli potrzebujesz rekurencji i używasz
bash
:Zauważ, że wszystkie te podejścia mają tę zaletę, że pracują nad dowolnymi nazwami plików, w tym ze spacjami, znakami nowej linii lub czymkolwiek innym.
źródło
sums.sha1
już tam jest (z poprzedniego uruchomienia), twoje rozwiązanie ją uwzględni.sh
, ale twoja odpowiedź może pomóc innym.z
zsh
:Glob zostanie rozszerzony przed dokonaniem przekierowania, więc
sums.sha1
nie zostanie uwzględniony, jeśli go nie będzie.D
polega na dołączeniu plików kropek (plików ukrytych) takfind
, jak by to było..
jest wybranie tylko zwykłych plików (takich jak twój-type f
).W
sums.sha1
każdym razie, aby je wykluczyć, gdyby miało to miejsce:Zauważ, że uruchamiają one jedną komendę shasum, więc możesz zobaczyć błąd „Zbyt długa lista Arg”, jeśli lista jest duża. Aby obejść ten problem:
Polecam używanie
./*
zamiast,*
aby uniknąć potencjalnych problemów z plikiem o nazwie-
.źródło
Jak już stwierdzono w innych odpowiedziach, problemem jest to, że powłoka otwiera się i tworzy
sums.sha1
plik przed wykonaniem potoku. Możesz użyć programu,sponge
który jest częściąmoreutils
pakietu wielu dystrybucji. W przeciwieństwie do przekierowania powłokisponge
, przed otwarciem pliku zaczeka, aż wszystko otrzyma. Zwykle jest używany, gdy chcesz zapisać plik, który czytasz w tym samym potoku.W twoim przypadku używa się go w następujący sposób:
źródło
Alternatywą dla find / xargs itp. Może być sha1deep. Prawdopodobnie jest w innym pakiecie - na moim pudełku jest w pakiecie md5deep.
Jak powiedzieli inni, sums.sha1 jest tworzony przez powłokę jeszcze przed uruchomieniem find. Sztuczka z
! -name sums.sha1
dofind
będzie działać, jak woliźródło