Find/Erweiterte Anwendungen

Aus Foxwiki

The “‑print” action lists the names of files separated by a newline

  • But it is common to pipe the output of find into xargs, which uses a space to separate file names
  • This can lead to problems if any found files contain spaces in their names, as the output doesn't use any quoting
  • In such cases, when the output of find contains a file name such as “foo bar” and is piped into another command, that command “sees” two file names, not one file name containing a space
  • Even without using xargs, you could have a problem if the file name contains a newline character, as most utilities expect one file name per line
  • In such cases, you can specify the action “‑print0” instead
  • This lists the found files separated not with a newline but with a null (or “”) character, which is not a legal character in Unix or Linux file names
  • Of course the command that reads the output of find must be able to handle such a list of file names
  • Many commands commonly used with find (such as tar or cpio) have special options to read in file names separated with NULs instead of spaces
  • Instead of having find list the files, it can run some command for each file found, using the “‑exec” action
  • The ‑exec is followed by some shell command line, ended with a semicolon (“;</nowiki>”)

(The semicolon must be quoted from the shell, so find can see it!) Within that command line, the word “{}” will expand out to the name of the found file

  • See below for some examples
  • You can use shell-style wildcards in the ‑name search argument: find . -name foo\*bar
  • This will search from the current directory down for foo*bar (that is, any filename that begins with foo and ends with bar)
  • Note that wildcards in the name argument must be quoted so the shell doesn't expand them before passing them to find
  • Also, unlike regular shell wildcards, these will match leading periods in filenames. (For example “find ‑name \*.txt” would match “.foo.txt”.)
  • You can search for other criteria beside the name
  • Also you can list multiple search criteria
  • When you have multiple criteria, any found files must match all listed criteria
  • That is, there is an implied Boolean AND operator between the listed search criteria. find also allows OR and NOT Boolean operators, as well as grouping, to combine search criteria in powerful ways (not shown here.)
  • Here's an example using two search criteria: find / -type f -mtime -7 | xargs tar -rf weekly_incremental.tar gzip weekly_incremental.tar
  • will find any regular files (i.e., not directories or other special files) with the criterion “‑type f”, and only those modified seven or fewer days ago (“‑mtime ‑7”)
  • Note the use of xargs, a handy utility that coverts a stream of input (in this case the output of find) into command line arguments for the supplied command (in this case tar, used to create a backup archive)
  • Using the tar option “‑c” is dangerous here; xargs may invoke tar several times if there are many files found, and each “‑c” will cause tar to over-write the previous invocation
  • The “‑r” option appends files to an archive
  • Other options such as those that would permit filenames containing spaces would be useful in a “production quality” backup script
  • Another use of xargs is illustrated below
  • This command will efficiently remove all files named core from your system (provided you run the command as root of course): find / -name core | xargs /bin/rm -f find / -name core -exec /bin/rm -f '{}' \; # same thing find / -name core -delete # same if using Gnu find</nowiki>
  • The last two forms run the rm command once per file, and are not as efficient as the first form; but they are safer if file names contain spaces or newlines
  • The first form can be made safer if rewritten to use “‑print0” instead of (the default) “‑print”. “‑exec” can be used more efficiently (see Using ‑execEfficiently below), but doing so means running the command once with many file names passed as arguments, and so has the same safety issues as with xargs
  • One of my favorite of the find criteria is used to locate files modified less than 10 minutes ago
  • I use this right after using some system administration tool, to learn which files got changed by that tool: find / -mmin -10
  • This search is also useful when I've downloaded some file but can't locate it, only in that case “‑cmin” may work better
  • Keep in mind neither of these criteria is standard; “‑mtime” and “‑ctime” are standard, but use days and not minutes
  • Another common use is to locate all files owned by a given user (“‑user 'username”)
  • This is useful when deleting user accounts
  • You can also find files with various permissions set. “‑perm /'permissions” means to find files with any of the specified permissions on, “‑perm -'permissions” means to find files with all of the specified permissions on, and “‑perm 'permissions” means to find files with exactly permissions. Permissions can be specified either symbolically (preferred) or with an octal number
  • The following will locate files that are writable by “others” (including symlinks, which should be writable by all): find . -perm -o=w

(Using ‑perm is more complex than this example shows

  • You should check both the POSIX documentation for find (which explains how the symbolic modes work) and the Gnu findman page (which describes the Gnu extensions)
  • When using find to locate files for backups, it often pays to use the “‑depth” option (really a criterion that is always true), which forces the output to be depth-first—that is, files first and then the directories containing them
  • This helps when the directories have restrictive permissions, and restoring the directory first could prevent the files from restoring at all (and would change the time stamp on the directory in any case)
  • Normally, find returns the directory first, before any of the files in that directory
  • This default behavior is useful when using the “‑prune” action to prevent find from examining any files you want to ignore:
  • find / -name /dev -prune ...other criteria | xargs tar
  • Using just “find / ‑name /dev ‑prune | xargs tar ...” won't work as most people might expect
  • This says to only find files named “/dev”, and then (if a directory) don't descend into it. So you only get the single directory name “/dev”! A better plan is to use the following: find / ! -path /dev\* |xargs
  • which says find everything except pathnames that start with “/dev”. The “!” means Boolean NOT
  • When specifying time with find options such as ‑mmin (minutes) or ‑mtime (24 hour periods, starting from now), you can specify a number “n” to mean exactly n, “‑n” to mean less than n, and “+n” to mean more than n
  • Fractional 24-hour periods are truncated! That means that “find ‑mtime +1” says to match files modified two or more days ago.
  • For example: find . -mtime 0 # find files modified between now and 1 day ago</nowiki> # (i.e., within the past 24 hours)</nowiki> find . -mtime -1 # find files modified less than 1 day ago</nowiki> # (i.e., within the past 24 hours, as before)</nowiki> find . -mtime 1 # find files modified between 24 and 48 hours ago</nowiki> find . -mtime +1 # find files modified more than 48 hours ago</nowiki> find . -mmin +5 -mmin -10 # find files modified between # 6 and 9 minutes ago</nowiki>

Weitere Lösungen

$ find -type f -printf '%T@ %p\0' | sort -zk 1nr | sed -z 's/^[^ ]* //' | tr '\0' '\n' | head -n 10 find -type f -printf '%T@ %p\n' | sort -k1 -n find -type f -print0 | xargs -0 stat -c "%y %n" | sort find -type f -print0 | xargs -0 stat -f "%m %Sm %N" | sort -rn

If you have not GNU utilities, you could use newlines as separators instead of nulls, but you'll lose support for filenames containing newlines

$ find -type f -printf '%T@ %p\n' | sort -k 1nr | sed 's/^[^ ]* //' 

Compare Filetree

$ find directory1 -type d -printf "%P\n" | sort > file1 find directory2 -type d -printf "%P\n" | sort | diff – file1

Verzeichnisse ausschließen

Use the prune switch, for example if you want to exclude the misc directory just add a -path ./misc -prune -o to your find command: find . -path ./misc -prune -o -name '*.txt' -print

  • Here is an example with multiple directories: find . -type d \( -path dir1 -o -path dir2 -o -path dir3 \) -prune -o -print find / \( -path /etc -o -path /dev -o -path /proc -o -path /sys \) -prune -o -name fstab -print
  • Here we exclude dir1, dir2 and dir3, since in find expressions it is an action, that acts on the criteria -path dir1 -o -path dir2 -o -path dir3 (if dir1 or dir2 or dir3), ANDed with type -d
  • Further action is -o print, just print.* shouldn't find . -name ./misc
  • be find . -path ./misc ...?
  • Hmm
  • This doesn't work for me either as it will include the ignored directory "./misc" in the output
  • Try to use misc instead of ./misc, that worked for me
  • It probably didn't work for you because you didn't add a -print (or any other action) explicitly after -name
  • In that case, both "sides" of -o end up printing, whereas if you use -print, only that side prints

Verwenden Sie den Schalter prune, wenn Sie z. B. das Verzeichnis misc ausschließen wollen, fügen Sie einfach ein -path ./misc -prune -o zu Ihrem find-Befehl hinzu: find . -pfad ./misc -prune -o -name '*.txt' -print

  • Hier ist ein Beispiel mit mehreren Verzeichnissen: find . -type d \( -pfad dir1 -o -pfad dir2 -o -pfad dir3 \) -prune -o -print find / \( -pfad /etc -o -pfad /dev -o -pfad /proc -o -pfad /sys \) -prune -o -name fstab -print
  • Hier schließen wir dir1, dir2 und dir3 aus, da es sich bei find-Ausdrücken um eine Aktion handelt, die auf die Kriterien -pfad dir1 -o -pfad dir2 -o -pfad dir3 (wenn dir1 oder dir2 oder dir3) wirkt, UNDiert mit Typ -d
  • Weitere Aktion ist -o print, nur print.* sollte nicht finden . -name ./misc
  • gefunden werden. -pfad ./misc ...?
  • Hmm
  • Das funktioniert bei mir auch nicht, da es das ignorierte Verzeichnis "./misc" in die Ausgabe einbezieht
  • Versuchen Sie, misc statt ./misc zu verwenden, das hat bei mir funktioniert
  • Wahrscheinlich hat es bei Ihnen nicht funktioniert, weil Sie nicht explizit ein -print (oder eine andere Aktion) nach -name hinzugefügt haben
  • In diesem Fall werden beide "Seiten" von -o gedruckt, während bei Verwendung von -print nur diese Seite gedruckt wird
All answers using -prune are wrong. The right way is

find -name "*.js" -not -path "./directory/*"* One of the comments in the accepted answer points out the problem. -prune does not exclude the directory itself, it exclude its content, which means you are going to get an unwanted line in the output with the excluded directory. –

  • Great answer
  • I'd add to this that you can exclude a directory at ANY level by changing the first
  • to *
  • so find -name "*.js" -not -path "*/omitme/*" would omit files from a directory named "omitme" at any level of depth
  • It still traverses all of the unwanted directory, though
  • I'm adding my own answer. :-)
  • Note, however, that the prune option only doesn't work if you don't use -print explicitly
  • It would be better to say "This is an alternative to using -prune"
  • The answers suggesting -prune are clearly not wrong, they just aren't the way you would do it

Siehe auch