Tag Info

Hot answers tagged

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 ...


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 ...


8

If you want to crawl on dirs and subdirs: find /home/place/to/crawl -type f -exec file --mime-type {} \; | awk '{if ($NF == "image/jpeg") print $0 }' What it does? Search all inodes with the type file Execute the command file, to get a jpeg header of the file like: image/jpeg awk Edit: Added @Franklin tip, to use file with -i to use the mime string ...


6

grep searches for the first argument (the pattern) in the files passed on the command line or stdin if no files are passed. Without the quote your shell will expand lect* to all the files in the directory that begin with lect. Your command will then be: grep lect1.txt lect2.doc lect3.doc which means search for the text lect1.txt in both .doc files. ...


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

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" ...


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 ...


4

If I undersood the question correctly you need files in myfiles which do not have symlinks in images: #!/bin/bash OIFS="$IFS" IFS=$'\n' files="$(find myfiles/ -type f -name '*.jpg' -or -name '*.cr2')" for f in $files; do list="$(find -L images/ -xtype l -samefile "$f")" if [[ "$list" == "" ]]; then echo "$f does not have symlink." fi ...


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 \) ...


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

With zsh: print -rl ${(0)^"$(locate -0 ...)"}(N.) (0) is a parameter expansion flag that splits on NUL characters (as we use locate -0), short for (ps:\0:). With ^, instead of adding (N.) at the end of the array, we add it to each element. (N.) is a glob qualifier, . to match only regular files, N to remove the element if it doesn't match (doesn't exist ...


3

This is about as inelegant as the other answers, but maybe less inefficient: locate --regex --basename "xfce4-keyboard-overlay$" | while IFS= read -r f; do [ -f "$f" ] && printf "%s\n" "$f"; done (broken into two lines for readability).  The above will handle names containing spaces.  The IFS= seems to be necessary to handle names with ...


3

Perhaps simply piping the output of find into grep would do the trick: if find . -name test.txt -size 156c | grep -q .; then echo Found; fi The call to find will have no output unless a file matching the name and size conditions you set is found, and grep . will have exit status 0 ("true") only if its input is non-empty. Option -q asks to not print any ...


3

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


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

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 ...


2

With GNU find (the implementation on non-embedded Linux and Cygwin): find /search/location -type l -xtype d With find implementations that lack the -xtype primary, you can use two invocations of find, one to filter symbolic links and one to filter the ones that point to directories: find /search/location -type l -exec sh -c 'find "$@" -L -type d -print' ...


2

I'd use this kind of construct as a starting point find / -type d -print0 | xargs -0 -I'{}' sh -c 'ls -ltr {} | tail -1' Caveat: it doesn't like empty directories (total 0 is output).


2

Probably this would be better: combination of find and shell find / -type d -print0 | while read -r -d '' dir; do ls -ltr "$dir" | sed '$!d' done find will output each directory found, using the null byte instead of a newline to separate them. This stream is fed into a while loop, using read -d '' to extract each null-delimited directory name. Then, ...


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

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

I assume that the files under myfiles are not symbolic links, and that none of the file names contain newlines. (My approach can still work if these assumptions are violated but it gets more complicated.) I also assume that you have the common readlink utility and that it supports -f to canonicalize paths, which is the case on Linux (both GNU and BusyBox), ...


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

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

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

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

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.



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