Tag Info

Hot answers tagged

25

From the findutils find manpage: If no expression is given, the expression -print is used (but you should probably consider using -print0 instead, anyway). (-print is a find expression.) The POSIX documentation confirms this: If no expression is present, -print shall be used as the expression. So find . is exactly equivalent to find . -print; ...


24

That's a really nice catch. From a quick look at the source code for GNU find, I would say this boils down to how fnmatch behaves on invalid byte sequences (pred_name_common in pred.c): b = fnmatch (str, base, flags) == 0; (...) return b; This code tests the return value of fnmatch for equality with 0, but does not check for errors; this results in any ...


14

-print is the default action. Some find predicates are considered as actions as opposed to filters or conditions. For instance, -type f is not an action. -exec is an action even though it can also be used as a condition. Actions include -print, -exec and -ok. Some find implementations have other non-standard action predicates like the -print0, -printf, ...


13

find -name option uses shell pattern matching notation to perform matching filename. * is a pattern matching multiple characters, shall match a string of zero or more characters. find uses fnmatch to check pattern matching, so you can use ltrace to check the result: $ touch $'\U1212'aa $ touch D$'\351'sinstaller $ LC_ALL=en_US.utf8 ltrace -e fnmatch find ...


7

They are the same, they both write out the entire directory hierarchy from the current directory. From POSIX find documentation: The following commands are equivalent: find . find . -print


6

Try this: touch -d"April 13 3 AM" file1 touch -d"April 13 9 AM" file2 find . -newer file1 ! -newer file2 -exec grep -l "pcV6URY" {} + rm file1 file2 How it works find can work directly with times but touch handles human-style dates better: touch -d"April 13 3 AM" file1; touch -d"April 13 9 AM" file2 This creates two files to mark the beginning and end ...


5

With GNU xargs: ack -l --print0 foo | xargs -r0 rm -- ack's --print0 and xargs' -0 cause ack and xargs to write and read using NUL as the delimiter, which guarantees proper filename handling. Without it, xargs will accept a far more wide range of characters as a delimiter.


5

For your -name version, instead of ! -name '*[done]*' you need ! -name '*\[done\]*' - otherwise it's taking the letters in brackets as a character set, and thus excluding anything that includes the letter "d" or "o" or "n" or "e" (and all of your filenames contain "e"). You were then negating that condition a second time, so that rather than excluding all ...


5

You've got this code: for file in *.mkv *avi *mp4 *flv *ogg *mov; do target="${file%.*}.mkv" ffmpeg -i "$file" "$target" && rm -rf "$file" done which runs in the current directory. To turn it into a recursive process you have a couple of choices. The easiest (IMO) is to use find as you suggested. The syntax for find is very "un-UNIX-like" ...


4

Some thoughts, almost all of which include -prune (why do you want to avoid this?): If you have a consistent and known set of local filesystem types, use something like find / \( -fstype rootfs -o -fstype ext4 -o -prune \) ...others... -print If you have a known set of pseudo-filesystem types, use something like find / \( -fstype tmpfs -o -fstype udev \) ...


4

Hard links. That's the only type for which its even possible to count. Pretty much every find option is something fairly trivially obtained for each file; the hard link count comes from stat (and is also displayed by ls, by the way). (To count symlinks, you'd have to examine every symlink and check where it points. But that's not even possible—symlinks can ...


3

Because you told it to scan starting at / (root). It does what you tell it to do.


3

Example snippet without piping (assumes you are giving the path as argument): #!/bin/bash backup_dir=/backup/ OIFS="$IFS" IFS=$'\n' files="$(find "$1" -type f -name '*.mkv' -or -name '*.avi' -or -name '*.mp4' -or -name '*.ogg' -or -name '*.mov' -or -name '*.flv')" for f in $files; do # get path d="${f%/*}" # get filename b="$(basename ...


3

With POSIX find: find . \( -name '*.mkv' -o -name '*avi' -o -name '*mp4' -o -name '*flv' -o \ -name '*ogg' -o -name '*mov' \) -exec sh -c ' for file do target="${file%.*}.mkv" echo ffmpeg -i "$file" "$target" done' sh {} + Replace echo with whatever command you want to use. If you have GNU find or BSD find, you can use -regex: find ...


3

find . -name PKA.dump -type f -exec awk ' FNR == 20 {print; nextfile}' {} + nextfile, where available (GNU awk and some others like FreeBSD's and recent versions of mawk and soon to be added to the standard) will skip to the next file. Where not, it will be ignored (it's just like dereferencing a nextfile variable); it will still work but read the files ...


3

To exclude specific paths, on Linux: find / -path /sys -prune -o -path /proc -prune -o -type d Another approach is to tell find not to recurse under different filesystems. find / -xdev -type d You could also use locate to query a database of file names (usually updated nightly) instead of the live system. locate '*' | shuf -n 1


3

In Linux there is no difference, but other systems (like AIX for instance) need -print if you want the output of the command displayed on your screen.


2

rm's stdin (where it reads the prompt answer from) is /dev/null (set by GNU xargs, some other xargs implementations would keep it as the pipe from ls). Your sh is getting many arguments at once, but you're only processing one ($1). Also note that the newline character is as valid as any in a file name which is why you generally can't process the output of ...


2

Use single quotes instead of double quotes, so that backticks and $ don't get interpreted by the original shell: find . -maxdepth 1 -type d -name 'acer' -exec sh -c 'echo {} $(ls {} | wc -l)' \; For the second question, I would put what you want to do into a separate script, that takes the directory name as an argument. Then do: find . -maxdepth 1 -type ...


2

This finds malformed images and stores their names in names.txt: find -name '*.jpg' -exec bash -c 'identify "$1" &>/dev/null || echo "$1">>names.txt' none {} \; How it works find -name '*.jpg' This starts up find as usual. -exec bash -c 'identify "$1" &>/dev/null || echo "$1" >names.txt' none {} \; This runs identify on each ...


2

Portably/standardly: find . -type f -exec grep 1234-5678 /dev/null {} + Some grep implementations have -r or -R options to search in files recursively. The behaviour varies from implementation to implementation though. With the grep found in AIX 6.1 for instance, you'll probably want to use the -R option1. Beware though that contrary to the find ...


2

You don't need to recursively enumerate directories to delete them with rm -rf; you can simply list the top-level directories you want to delete. To determine whether a directory entry is a directory rather than a file, you can use find's -type d test; using . isn't a good indicator. The following should work for you: find * -maxdepth 0 ! -name encoded ...


2

If you don't mind using two different commands for the file names and content, the below commands will help you. find /sys -name "*filesystem*" The above command will find all the files/directories with "filesystem" as part of the filename/directoryname. grep -rn "filesystem" /sys/* The above command will look for all the files containing "filesystem" ...


2

Try find . -name env2.cfg -execdir cp {} env3.cfg \; By replacing exec to execdir. It will mean that your 'action' (cp) will take place inside the folder where the file (env2.cfg) have been found.


2

Your example copies all env2.cfg files to the current working directory, which is ".". You need to give the file found a new name, including its directory. This one worked for me: for file in $(find . -name env2.cfg); do backup=$(echo $file | sed 's/env2.cfg/env3.cfg/'); cp $file $backup; done edit: Or the even more elegant way, so you don't have to ...


2

ls -ltr file*: This command just list the contents of the current directory in the long listing format (-l), sorted by modification time (-t) in reverse order (-r) of all files and directories beginning with file*. find ./ -name file*: That command searches trough the whole directory structure under the current working directory and all its subdirectories ...


2

The find version will also find files matching that name in subdirectories. Note you should quote or escape the * in the filename pattern; if the pattern matches a file in the local directory it will expand to that name and find will only find exactly that name. If it matches more than one filename then you will get an error because those multiple filenames ...


2

If your grep supports reading NUL-delimited lines (like GNU grep with -z), you can use it to test if anything was output by find: find /some/path -print0 | grep -qz . To pipe the data to another command, you can remove the -q option, letting grep pass on the data unaltered while still reporting an error if nothing came through: find /some/path -print0 | ...


1

find does not sort the files, it lists them out in the order it finds them. It also traverses directories in the order it finds them. You cannot make any assumptions about the order but I believe it will be repeatable in the sense that if you run find again, you'll get the same order. On Linux, files are not stored in alphabetical order. Maybe they are on ...


1

Welcome to Unix :) To answer some of your minor questions that answers to the main question didn't cover: Shell scripting certainly has some rough edges, since a lot of things break on file names with spaces. And almost everything breaks on filenames with newlines (fortunately, nobody makes those on purpose). Filenames containing glob characters like [, ...



Only top voted, non community-wiki answers of a minimum length are eligible