Linux find exec md5sum, only the sum like this (fullpath TAB size TAB mtime TAB ctime TAB md5) - find

I want to view for the files in /var/www the following data:
fullpath size mtime ctime md5
I ran the following command:
find /var/www/ -maxdepth 1 ! -type d -printf '%p\t%s\t%t\t%c\t' -exec md5sum {} \;
which gives me:
(fullpath size mtime ctime md5 fullpath)
/var/www/intranet/admin/tpl/view.tpl.php 1448 Wed Dec 16 18:51:06.0000000000 2015 Fri Sep 15 09:08:36.0805775786 2017 e0b7dacaf7c90fb0fbe7a69c331e36aa /var/www/intranet/admin/tpl/view.tpl.php
How can I filter the last fullpath?????? I do not want to show it. All fields are TAB separated.
I tried:
find /var/www/ -maxdepth 1 ! -type d -printf '%p\t%s\t%t\t%c\t'
-exec md5sum {} | awk '{print $1}'\;
for which I received the error: "find: missing argument to `-exec'"
find /var/www/ -maxdepth 1 ! -type d -printf '%p\t%s\t%t\t%c\t' -exec md5sum {} + | awk '{print $1}'
for which I got only the md5sum.
Thanks in advance!

Pipelines (|) are a shell-feature. To get shell features, one needs to invoke a shell:
find /var/www -maxdepth 1 ! -type d -printf '%p\t%s\t%t\t%c\t' -exec sh -c 'md5sum "$1" | awk '\''{print $1}'\' MD5 {} \;
Or, if you prefer commands spread over multiple lines:
find /var/www \
-maxdepth 1 \
! -type d \
-printf '%p\t%s\t%t\t%c\t' \
-exec sh -c 'md5sum "$1" | awk '\''{print $1}'\' MD5 {} \;
Notes
sh -c somestring invokes a shell and instructs it to execute whatever commands are in somestring.
sh -c somestring MD5 {} invokes the shell and executes somestring and assigns $0 to MD5 and $1 to whatever find substitutes for {}.
$0 is only used by the shell when it creates error messages and otherwise unimportant.
A complication is that our command, somestring, must contain both single quotes and double-quotes which is why we need escaped single-quotes.
In our case, we want somestring to be:
md5sum "$1" | awk '{print $1}'
To prevent the main shell from substituting in for $1, we need to put this inside single-quotes. However, we can't put single-quotes inside single-quotes. The workaround is to use this for our single-quoted string:
'md5sum "$1" | awk '\''{print $1}'\'

Related

Get current directory in find command and use in sed - one-liner

I'm using this to find files of a particular name in subdirectories, then editing some content:
find prod -type f -name "file.txt" -exec sed -i '' -e "s,^varname.*$, varname = \"$value\"," {} +
How can I get the name of the current directory (not the directory the script is executed in, rather the directory the file is found in) and insert it into the replace text? Something like:
find prod -type f -name "file.txt" -exec sed -i '' -e "s,^ varname.*$, varname = \"$value/$dirname\"," {} +
I'm hoping to keep it as a one-liner. My most recent attempt was this, but the replacement didn't work and I feel there must be a simpler syntax:
find prod -type f -name "file.txt" -exec sh -c '
for file do
dirname=${file%/*}
done' sed -i '' -e "s,^varname.*$, varname = \"$value/$dirname\"," {} +
Example:
value=bar
file.txt input:
varname = “foo”
file.txt output:
varname = “bar/directory_name”
You can do this with GNU awk in the same way:
The sed command you make use of can be replaced with:
$ awk --inplace -v v="$value" '(FNR==1){d=FILENAME;sub("/[^/]*$","",d)}/^varname/{$0="varname = "v"/"d}1'
So your find woud read:
$ find prod -type f -name "file.txt" -exec awk --inplace -v v="$value" '(FNR==1){d=FILENAME;sub("/[^/]*$","",d)}/^varname/{$0="varname = "v"/"d}1' {} \;
This might work for you (GNU sed & parallel):
find prod -type f -name "file.txt" |
parallel -qa- --link sed -i 's#\(varname=\).*#\1"{2}{1//}"#' {1} ::: $value
We supply 2 sources to the parallel command. The first source is the list of files from the find command using the parallel option -a -. The second source is the variable $value, being only a single value it is linked to the first source using the parallel option --link. The sed command is quoted using the parallel option -q and normal regexp rules apply excepting that the values {2} and {1//} are first interpreted by parallel to represent the second source and the directory of the first source respectively.
N.B. To check the commands to parallel are as you desire, use the --dryrun option and check the output before running for real.
You need to use -execdir and spawn a shell:
find ... -execdir \
bash -c 'sed -i "" -e "s,^ varname.*$, varname = \"$value/${PWD}\"," "$1"' -- {} +
-execdir runs sed in the parent folder of the file instead of the folder from where you run find. This allows to use
$PWD.
Further note: I calling bash with two arguments:
-exec bash -c '... code ...' -- {}
^^ ^^
I'm passing the -- as a placeholder. When called with -c, bash starts to index arguments at $0 instead of $1. ($0 would normally contain the script's name). That allows to use $1 for the filename from {} which is imo more readable and understandable.

find dir xargs rm output to a file.log

I have a bash script, in the end will find folders with modified timestamps greater than 5 days then pipe it to xargs to rm. This is working fine and to print the command I am using -t option for the xargs as well. But I need this output written to a log file.
so my command line is as follows :
find /tmp/test -type d -mtime +5 -print0 | xargs -t -0 -I {} /bin/rm -rf '{}'
I would like to get the output to know which all folders are deleted to a file named rmdirs.log
I tried redirecting it to a file but like below and it wont work;
find /tmp/test -type d -mtime +5 -print0 | xargs -t -0 -I {} /bin/rm -rf '{}' >> rmdirs.log
Any help would be much appreciated.
I created a test environment with touch. This properly deletes the directory and logs the ones deleted to rmdirs.log file.
touch -t 202201010000 tmp/test/old
touch tmp/test/new
find tmp/test -type d -mtime +5 -print | \
tee -a rmdirs.log | \
tr '\12' '\0' | \
xargs -0 -I {} /bin/rm -rf {}
Use teeto append (-a) to the rmdirs.log file.
Use tr to convert the newlines (\12) to null (\0) for safety.
Finally run xargs to remove the files.

Using Sed and Find with Grep Linux

I am writing a script that will saech for php files that contain a phrase and I would like that phrase replaced with a new one below is my little script but it is not working it searches ok but does not work with the search and replace section
find . -type f -name "*.php" -exec grep -H "define('DB_HOST', 'localhost');" {} \; | xargs sed -i "define('DB_HOST', 'localhost');/define('DB_HOST', '10.0.0.1');/g"
can someone explain to me what i am doing wrong
many thanks
Joe
did you forget the 's/' at the beggining of the sed expression? As in
sed 's/expression1/expression2/g'
You seem to have
sed 'espression1/expression2/g'
Edit
Another thing: You don't need to use xarg here. You can use multiple -exec flags - and it will to each only if all the previous succeeded:
find . -name '*.php' -exec grep 'whatever' {} \; -exec sed -i 's/whatever/you want/g' {} \;
This will work:
find . -type f -name "*.php" -exec grep -l "define('DB_HOST', 'localhost');" {} \; | xargs sed -i "s/define('DB_HOST', 'localhost');/define('DB_HOST', '10.0.0.1');/g"
Corrections
Missing s/ in sed search and replace command
use grep -l instead of grep -H

Can find tell me if no files exist?

On my FTP server, I look for files delivered in the past day and remove in-place header & trailer records.
find . -type f -name "CDC*" -ctime -1 -exec sed -i'' -e '1d' -e '$d' '{}' \;
This works well.
I want to automate this in a script. But how can I send myself an email notification is no files are found? I am thinking of doing something like:
find . -type f -name "CDC*" -ctime -1 -exec sed -i'' -e '1d' -e '$d' '{}' \;
EXIT=`echo $?`
case $EXIT in
0) ...do stuff...
*) mail....exit
esac;;
There has to a better way, right?
I'm pretty sure that you could take whatever command you need to do the search, and pipe a wc -l on to the end of it. Then use an if statement to check for zero. So using your example above.
NUMLINES=`find . -type f -name "CDC*" -ctime -1 -exec sed -i'' -e '1d' -e '$d' '{}' \ | wc -l`
if [ "$NUMLINES" -eq 0 ] ; then
foo
fi
Or something like that. I didn't check if that syntax is correct though. But i'm sure you get my drift

Linux: Using find and grep to find a keyword in files and count occurrences

I'm using executing this bash commands inside a search script I've built with php:
find myFolder -type f -exec grep -r KEYWORD {} +
find myFolder -type f -exec grep -r KEYWORD {} + | wc -l
find myFolder -type f | wc -l
The first line gives me back the filenames where KEYWORD was found.
The second line gives me the number of occurrences and the third line the total number of files.
Is there a way to do this more elegantly and faster?
You can get more efficiency if you avoid -exec, which makes one fork per file match. xargs is a better choice here. So I would do something like this:
find myFolder -type f -print0 | xargs -0 grep KEYWORD
find myFolder -type f -print0 | xargs -0 grep KEYWORD | wc -l
The last one should be OK, at least with GNU find.
The -print0 and -0 ensure that filenames with spaces in them are handled correctly.
Note that grep -r` implies recursive grepping, but as you're only supplying one filename in each invocation it is redundant.