Hot answers tagged

13

Try: grep -rl --null --include '*.txt' LINUX/UNIX . | xargs -0r cp -t /path/to/dest Because this command uses NUL-separation, it is safe for all file names including those with difficult names that include blanks, tabs, or even newlines. The above requires GNU cp. For BSD/OSX, try: grep -rl --null --include '*.txt' LINUX/UNIX . | xargs -0 sh -c 'cp "$@"...


12

awk 'FNR == 1 { f1=f2=f3=0; }; /one/ { f1++ }; /two/ { f2++ }; /three/ { f3++ }; f1 && f2 && f3 { print FILENAME; nextfile; }' * If you want to automatically handle gzipped files, either run this in a loop with zcat (slow and inefficient because you'll be forking awk many times in a loop, once ...


12

More portably (POSIX features only): find . -type f -name '*.txt' -exec grep -q LINUX/UNIX \; -exec cp {} /path/to/dest \;


11

Set record separator to . so that awk will treat whole file as a one line: awk -v RS='.' '/one/&&/two/&&/three/{print FILENAME}' * Similarly with perl: perl -ln00e '/one/&&/two/&&/three/ && print $ARGV' *


7

One more way, assuming GNU find(1), just for fun: find $PWD -type f -name "file.txt" -printf '%p '


6

Assuming your find supports it, use the -execdir option instead of -exec find * -name 'foo' -execdir pwd \; If it doesn't, please provide details of your platform and/or distribution (as appropriate).


5

Because when you use just *net* (without any quoting or escaping), it will be expanded by the shell as the (existing) net file/directory in the current directory before the find command run. So the command becomes: find . -name net As you can see it is just matching net, so usbnet.ko will not be matched. Also note that, without quoting and escaping, if ...


5

You can replace the LF character with a space using the 'tr' command tr '\012' ' ' < path.txt This can be part of the original command: find $PWD -type f -name "file.txt" | tr '\012' ' ' > paths.txt


5

Using GNU find: #!/bin/sh dir='/mnt/data/project_data/web_collab/mailbox/' sr_today=$(find "$dir" \ ! -path '*/000000/*' \ -newermt '12am today' \ -ipath '*/sr_pdf/*.pdf' | wc -l) GNU find's -newermt option understands the same date formats as GNU date -d and touch -d. See man find and search for -...


4

You can use, paste too, find . -type f -name "path.txt" -exec paste -d' ' -s {} \; > path.txt


4

One simple way would be to pipe the find output through xargs (whose default action when no explicit command is given is to echo its arguments) find $PWD -type f -name "file.txt" | xargs > paths.txt Unlike simply replacing all the newlines with spaces, this preserves the final newline.


4

This will go through your files and set the executable bit according to whether file believes that the file should be executable: find /var/www/html -type f -exec bash -c 'if file -b "$1" | grep -q executable; then chmod +x "$1"; else chmod -x "$1"; fi' None {} \; The find command is very similar to yours. The change is the addition of the bash commands. ...


4

find ./path/to/your/drive -type f -name '*.jpg' -exec du -ch {} + Or much faster find /path/to/your/drive -name "*.jpg" -print0 | du -ch --files0-from=- Or simply, du -ch /path/to/your/drive/*.jpg | grep total Or with help of awk, find /path/to/your/drive -iname "*.jpg" -ls | awk '{total += $7} END {print total}' On my system file size shows on ...


4

find . -depth -iname proj -type d -execdir mv {} test \; You need a find implementation with support for the non-standard -execdir predicate, but find implementations that support -iname generally also support -execdir in my experience.


4

If you have GNU find, you can print the path using the %h format specifier %h Leading directories of file's name (all but the last ele‐ ment). If the file name contains no slashes (since it is in the current directory) the %h specifier expands to ".". So for example you could do find . -name 'results.out' -...


3

For compressed files, you could loop over each file and decompress first. Then, with a slightly modified version of the other answers, you can do: for f in *; do zcat -f "$f" | perl -ln00e '/one/&&/two/&&/three/ && exit(0); }{ exit(1)' && printf '%s\n' "$f" done The Perl script will exit with 0 status (success)...


3

A simple loop of checking the current directory and if it's not found then strip off the last component would work #!/bin/bash wantfile="$1" dir=$(realpath .) found="" while [ -z "$found" -a -n "$dir" ] do if [ -e "$dir/$wantfile" ] then found="$dir/$wantfile" fi dir=${dir%/*} done if [ -z "$found" ] then echo Can not find: $wantfile else ...


3

You can also take advantage of the fact that the shell strips newlines from command substitutions. So, instead of find $PWD -type f -name "file.txt" > paths.txt, you can do (note that you don't need the $PWD, it is the default value for find): echo $(find $PWD -type f -name "file.txt") > paths.txt or printf '%s ' $(find $PWD -type f -name "file.txt"...


3

Your command $ find . -name 'segment*' | xargs -n1 -P4 sh someFunction.sh has the effect that at most four copies of the someFunction.sh shell script will be started (-P 4) in parallel (new ones will be spawed as soon as the old ones are done), each one getting one filename as its argument (-n 1). This means that each invocation of your script will look ...


3

The error is occurring because find doesn't know when to stop. If you run find | head, when head gets its ten lines and exits, the next time find tries to write a filename, it'll get a SIGPIPE (letting it know that the other end of the pipe is broken or closed), and find will gracefully exit. But here, find isn't writing anything, ls is. find can see that ...


3

To get ls to display the folder name instead of listing its contents, use its -d argument such as: ls -ld ~


2

The find command allows you to limit what files are matched. You can then call your script with the exec option e.g. find . \( -name '*.mp3' -o -name '*.avi' \) -exec /path/to/your/script.sh Now your script will be called for each mp3/avi file in the tree. A simple test to show this would be to have script.sh read something like #!/bin/bash echo ...


2

You can do this with find alone using the -exec action: find /location -size 1033c -exec cat {} + {} will be expanded to the files found and + will enable us to read as many arguments as possible per invocation of cat, as cat can take multiple arguments. If your find does not have the + extension or you want to read the files one by one: find /location -...


2

You could use something like this assuming someFunction.sh is in your working directory. find . -name 'segment*' -print0| xargs -0 -n1 -P4 ./someFunction.sh The -print0 and -0 allow for files with spaces in the name (A common problem). In my someFunction.sh I have #!/bin/bash echo "Arg: " $1 cat $1 Which simply echo's out the file name then ...


2

Assuming your files have sane names (i.e. they don't have embedded newlines), something like this should work: find . -mtime +60 | fgrep -v -x -f exceptions.txt | xargs -d '\n' rm -f Replace rm -f with ls -1 for a dry run first. Put paths exactly as they are printed by find in exceptions.txt.


2

I think this must be one of the silliest command piplines I ever have concocted: $ find . -type l -name "Math*" -print0 | xargs -0 -n 1 -IXXX find XXX/ -type f -name "*.tex" -print0 | xargs -0 fgrep "word" Find all symbolic links called Math*. Do find again on each found path, looking for *.tex files. The xargs need to use -n 1 to call find with no ...


2

Of all the solutions proposed so far, my original solution using grep is the fastest one, finishing in 25 seconds. It's drawback is that it's tedious to add and remove keywords. So I came up with a script (dubbed multi) that simulates the behavior, but allows to change the syntax: #!/bin/bash # Usage: multi [z]grep PATTERNS -- FILES command=$1 # first ...


2

One way to do it: #! /bin/sh dir=$(pwd -P) while [ -n "$dir" -a ! -f "$dir/$1" ]; do dir=${dir%/*} done if [ -f "$dir/$1" ]; then printf '%s\n' "$dir/$1"; fi Replace pwd -P by pwd -L if you want to follow symlinks instead of checking physical directories.


2

I would do it in two find calls: One to find all zip files and then process them Another to deal with the regular files This is a little cumbersome, the complicated part is the awk call. It processes the output of unzip -l which is not very script friendly. It searches for lines starting with numbers (to get rid of the headers), gets rid of empty lines,...


2

You can collect the names into a variable fns and echo this at the end. Since you have a pipe you need to keep the variable in the same subshell as the while/do/done. ${fns:1} is a substring of the variable, dropping the initial extra comma. #!/bin/bash PATHX="/path/to/my/files" find "${PATHX}" -maxdepth 1 -type f -name "*.csv" | ( fns= while read d; ...



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