Mam listę plików, które chcę sprawdzić, czy istnieją w moim systemie plików. Myślałem o zrobieniu tego za pomocą find
:
for f in $(cat file_list); do
find . -name $f > /dev/null || print $f
done
(za pomocą zsh
), ale to nie działa, ponieważ find
wydaje się, że kończy działanie 0
niezależnie od tego, czy znajdzie plik. Chyba mogę przekazać go za pośrednictwem innego testu, który sprawdza, czy find
produkuje żadnego wyjścia (surowy, ale skuteczne byłoby wymienić > /dev/null
z |grep ''
), ale to uczucie za pomocą troll złapać kozę (inne narodowości mogą powiedzieć coś o młotami i orzechami ).
Czy istnieje sposób, aby przekonać find
mnie do podania użytecznej wartości wyjściowej? A przynajmniej żeby uzyskać listę tych plików, których nie znaleziono? (Mogę sobie wyobrazić, że to drugie może być łatwiejsze dzięki sprytnemu wyborowi logicznych połączeń, ale zawsze staram się to rozgryźć.)
Tło / Motywacja: Mam „główną” kopię zapasową i chcę sprawdzić, czy niektóre pliki na mojej lokalnej maszynie istnieją na mojej głównej kopii zapasowej przed ich usunięciem (aby utworzyć trochę miejsca). Zrobiłem więc listę plików, ssh
edytując je na komputerze głównym, i wtedy nie mogłem znaleźć najlepszego sposobu na znalezienie brakujących plików.
locate
.locate
nie pokazuje aktualnego stanu systemu plików, może to być dzień, a nawet tydzień. Jest to odpowiednie jako baza do testowania kopii zapasowych.Odpowiedzi:
find
uznaje brak znalezienia za szczególny przypadek sukcesu (nie wystąpił błąd). Ogólnym sposobem sprawdzenia, czy plikifind
spełniają określone kryteria, jest sprawdzenie, czy dane wyjściowefind
są puste. Aby uzyskać lepszą wydajność, gdy istnieją pasujące pliki, użyj-quit
GNU find, aby sprawić, że zakończy się przy pierwszym dopasowaniu, lubhead
(head -c 1
jeśli jest dostępny, w innym przypadku,head -n 1
co jest standardem) w innych systemach, aby umrzeć z powodu pękniętej rury, a nie generować długi wynik.W bash ≥4 lub zsh nie potrzebujesz zewnętrznego
find
polecenia do prostego dopasowania nazwy: możesz użyć**/$name
. Wersja Bash:Wersja Zsh na podobnej zasadzie:
Lub tutaj jest krótszy, ale bardziej tajemniczy sposób testowania istnienia pliku pasującego do wzorca. Kwalifikator glob
N
powoduje, że dane wyjściowe są puste, jeśli nie ma dopasowania,[1]
zachowuje tylko pierwsze dopasowanie ie:REPLY=true:
zmienia każde dopasowanie, aby rozwinąć do1
zamiast nazwy dopasowanego pliku. Tak**/"$name"(Ne:REPLY=true:[1]) false
rozwija siętrue false
, jeśli jest mecz, albo po prostufalse
, jeśli nie ma odpowiednika.Bardziej efektywne byłoby połączenie wszystkich nazwisk w jednym wyszukiwaniu. Jeśli liczba wzorców nie jest zbyt duża dla limitu długości twojego systemu w linii poleceń, możesz połączyć wszystkie nazwy za pomocą
-o
, wykonać pojedynczefind
wywołanie i przetworzyć dane wyjściowe. Jeśli żadna z nazw nie zawiera metaznaków powłoki (tak więc nazwy są równieżfind
wzorami), oto sposób na przetworzenie z awk (nieprzetestowane):Innym podejściem byłoby użycie Perla i
File::Find
, co ułatwia uruchomienie kodu Perla dla wszystkich plików w katalogu.Alternatywnym podejściem jest wygenerowanie listy nazw plików po obu stronach i praca nad porównaniem tekstu. Wersja Zsh:
źródło
zsh
rozwiązanie ze**
składnią. Jest to bardzo proste rozwiązanie i chociaż może nie być najbardziej wydajne z punktu widzenia maszyny , jest prawdopodobnie najbardziej wydajne z mojego punktu widzenia! Również pierwsze rozwiązanie tutaj odpowiada na rzeczywiste pytanie , ponieważ skręca sięfind
w coś, w czym kod wyjścia odróżnia „Mam dopasowanie” od „Nie dostałem dopasowania”.Można użyćstat
do ustalenia, czy plik istnieje w systemie plików.Powinieneś użyć wbudowanych funkcji powłoki, aby sprawdzić, czy istnieją pliki.
„Test” jest opcjonalny i skrypt faktycznie będzie bez niego działał, ale zostawiłem go dla czytelności.
Edycja: Jeśli naprawdę nie masz innej opcji, jak pracować nad listą nazw plików bez ścieżek, sugeruję, abyś zbudował listę plików raz za pomocą funkcji find, a następnie iteruj ją za pomocą grep, aby dowiedzieć się, które pliki tam są.
Uwaga:
źródło
Pierwszym uproszczonym podejściem może być:
a) posortuj listę plików:
znaleźć braki lub
znaleźć mecze
Wady:
find może wyszukać wiele plików jednocześnie, przy pewnym przygotowaniu:
znajdź -nazwa a.plik -lub -nazwa -b.plik -lub -nazwa c.plik ...
Czy lokalizacja może być opcją? Ponownie przyjęto wstępnie przygotowaną listę plików:
Wyszukiwanie foo.bar nie będzie pasować do pliku foo.ba lub oo.bar z konstruktem --regexp (nie należy go mylić za pomocą wyrażenia regularnego bez p).
Możesz określić konkretną bazę danych do zlokalizowania i musisz ją zaktualizować przed rozpoczęciem wyszukiwania, jeśli potrzebujesz najnowszych wyników.
źródło
Myślę, że to też może być przydatne.
Jest to rozwiązanie jednoliniowe, na wypadek gdybyś wybrał „listę” jako prawdziwe pliki, które chcesz zsynchronizować z innym folderem:
aby pomóc w czytaniu:
ten przykład wyklucza tworzenie kopii zapasowych plików „* ~” i ograniczenia do zwykłego typu pliku „-type f”
źródło
Może?
źródło
Dlaczego po prostu nie porównać długości listy zapytań z długością listy wyników?
źródło