Polecenie `find` nie zwraca żadnych wyników podczas dodawania -exec

1

Kiedy uruchamiam findz tymi argumentami, zwraca tysiące plików:

steven@nook:/mnt/station/media $ sudo find . -not -user steven -or -not -group users | wc
   3508   17479  245851
steven@nook:/mnt/station/media $

Po dodaniu -execargumentu zachowuje się, jakby findnie zwrócił żadnych wyników, a kod powrotu oznacza sukces:

steven@nook:/mnt/station/media $ sudo find . -not -user steven -or -not -group users -exec echo {} \;
steven@nook:/mnt/station/media $ echo $?
0
steven@nook:/mnt/station/media $

(Moim celem jest wykorzystanie -exec chown -v steven:users {} \;wyników (stąd sudo), ale używam -exec echo {} \;powyżej, aby lepiej zilustrować problem i wykluczyć chownjako czynnik przyczyniający się.)

Używam GNU find w magazynie Bash na Ubuntu Xenial:

steven@nook:/mnt/station/media $ find --version
find (GNU findutils) 4.7.0-git
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Written by Eric B. Decker, James Youngman, and Kevin Dalley.
Features enabled: D_TYPE O_NOFOLLOW(enabled) LEAF_OPTIMISATION FTS(FTS_CWDFD) CBO(level=2)
steven@nook:/mnt/station/media $ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.04
DISTRIB_CODENAME=xenial
DISTRIB_DESCRIPTION="Ubuntu 16.04.2 LTS"
steven@nook:/mnt/station/media $ echo $SHELL
/bin/bash
steven@nook:/mnt/station/media $
Steven K.
źródło

Odpowiedzi:

4

Wynika to z faktu, że sąsiednie operacje łączą się z domniemanym -andmocniejszym niż jawne -or, a także dlatego, że ze strony podręcznika find(1)„Jeśli wyrażenie nie zawiera żadnych działań innych niż -prune, -print jest wykonywane na wszystkich plikach, dla których wyrażenie jest prawdziwe”.

Oznacza to, że findpatrzy na wyrażenie w twoim pierwszym przykładzie i widzi

(-not -user steven) -or (-not -group users)

i działa -printzgodnie z oczekiwaniami.

Find widzi jednak twój drugi przykład jako

(-not -user steven) -or ((-not -group users) -and -exec echo {})

To powinno powtórzyć wszystkie pliki należące do użytkownika Stevena i nie należące do użytkowników grupy.

Rozwiązaniem jest dodanie nawiasów ucieczkowych wokół wyrażenia przed -exec:

sudo find . \( -not -user steven -or -not -group users \) -exec echo {} \;
garyjohn
źródło
To załatwiło sprawę, dzięki. Świetne wyjaśnienie, w jaki sposób przeanalizowało ukryte grupowanie bez operatorów grupujących.
Steven K,
Myślę, że twoja odpowiedź byłaby korzystna, gdybyś wyraźnie wspomniał o następującym kluczowym zachowaniu expr1 -or expr2: „ expr2nie jest oceniany, jeśli expr1jest prawdziwy”. Trochę czasu zajęło mi zrozumienie, dlaczego napisałeś „należący do użytkownika Stevena”. To nie jest takie oczywiste.
Kamil Maciorowski,
1

Musisz wprowadzić dwie poprawki do linii poleceń.

Po pierwsze, nawiasy klamrowe polecenia exec muszą być poprzedzone znakiem zapytania lub cytowane, aby chronić je przed rozszerzaniem przez powłokę. Jest to wyraźnie wspomniane na stronie man find .
Na stronie podręcznika znajduje się również przykład wyjaśniający to wymaganie.

   find . -type f -exec file '{}' \;

   Runs  `file'  on  every file in or below the current directory.  Notice
   that the braces are enclosed in single quote marks to protect them from
   interpretation as shell script punctuation.  The semicolon is similarly
   protected by the use of a backslash, though single  quotes  could  have
   been used in that case also.

Po drugie, zakres i pierwszeństwo -orwyrażenia należy wyjaśnić w nawiasach (które również należy pominąć).

Po wprowadzeniu poprawek powinny działać:

sudo find . \( -not -user steven -or -not -group users \) -exec echo '{}' \;

FWIW Wolę przesyłać dane wyjściowe polecenia find i używać xargs, które zajmują się składnią -exec.

find . -not -user steven -or -not -group users | xargs sudo echo
trociny
źródło