What does this xargs command do? - linux

I'm very new to xargs and can't seem to understand what this command does. Specifically I get confused with the find part of it and the brackets. Any explanations are welcome.
xargs -I '{}' find '{}' -xdev -type d \( -perm -0002 -a ! -perm -1000 \)

All of this can be found in the xargs and find man pages
xargs -I '{}'
Is replace string, and will replace any occurrence of '{}' with the line from the input to xargs
find '{}'
Search the directory with the name held in '{}'
-xdev
Don't go to other filesytstems
-type d
Only search for directories
\(
Not 100% but i think these are just to group the last 2 args
-perm -0002 -a ! -perm -1000
Check permission contain 0002 and not 1000
-a is and
! is not
Look up permission bits if you are unsure what these represent.

Related

I want to get an output of the find command in shell script

Am trying to write a script that finds the files that are older than 10 hours from the sub-directories that are in the "HS_client_list". And send the Output to a file "find.log".
#!/bin/bash
while IFS= read -r line; do
echo Executing cd /moveit/$line
cd /moveit/$line
#Find files less than 600 minutes old.
find $PWD -type f -iname "*.enc" -mmin +600 -execdir basename '{}' ';' | xargs ls > /home/infa91punv/find.log
done < HS_client_list
However, the script is able to cd to the folders from HS_client_list(this file contents the name of the subdirectories) but, the find command (find $PWD -type f -iname "*.enc" -mmin +600 -execdir basename '{}' ';' | xargs ls > /home/infa91punv/find.log) is not working. The Output file is empty. But when I run find $PWD -type f -iname "*.enc" -mmin +600 -execdir basename '{}' ';' | xargs ls > /home/infa91punv/find.log as a command it works and from the script it doesn't.
You are overwriting the file in each iteration.
You can use xargs to perform find on multiple directories; but you have to use an alternate delimiter to avoid having xargs populate the {} in the -execdir command.
sed 's%^%/moveit/%' HS_client_list |
xargs -I '<>' find '<>' -type f -iname "*.enc" -mmin +600 -execdir basename {} \; > /home/infa91punv/find.log
The xargs ls did not seem to perform any useful functionality, so I took it out. Generally, don't use ls in scripts.
With GNU find, you could avoid the call to an external utility, and use the -printf predicate to print just the part of the path name that you care about.
For added efficiency, you could invoke a shell to collect the arguments:
sed 's%^%/moveit/%' HS_client_list |
xargs sh -c 'find "$#" -type f -iname "*.enc" -mmin +600 -execdir basename {} \;' _ >/home/infa91punv/find.log
This will run as many directories as possible in a single find invocation.
If you want to keep your loop, the solution is to put the redirection after done. I would still factor out the cd, and take care to quote the variable interpolation.
while IFS= read -r line; do
find /moveit/"$line" -type f -iname "*.enc" -mmin +600 -execdir basename '{}' ';'
done < HS_client_list >/home/infa91punv/find.log

Problems with understanding and combining linux terminal commands

First one :
We found several files and we have to copy that to kat4 and here is code, but it doesn't seem to work corectly
find /home/imk-prac/ -type f -size -13c -name '*\?plik\?*' -exec cp {} /home/inf-19/aduda/\*kat1\*/\*kat2\*/\*kat4\*/ \; 2> /dev/null
'cp' I assume that it is copy, but I don't know what 'exec' and '{}' do.
Second one:
find /home/imk-prac/ \( -type f -size -13c -name '*\?plik\?*' \) -o\( -type d -name '\[Kolo1\]*' \)2> /dev/null
Generally,I understand this line (except for '2' and '-o') , but I want to add looking for files which were modificated in less that 30 days and here is what I wanted to combine with upper command :
find /home/imk-prac/ -type f -mtime -30 -exec ls -l {} \; > /dev/null
As a result I wrote it down as:
find /home/imk-prac/ \( -type f -size -13c -name '*\?plik\?' -mtime -30 -exec ls -l{}\) -o \( -type d -name '\[Kolo1\]*' \) 2> /dev/null
but it doesn't work
Moreover, I wanted to add looking for files with speciefied quantity of symbols and I found this command:
grep -Po '(^|\s)\S{64}(\s|$)' file
But I have no idea how to combine all of those 3 upper commands.
I will be grateful for any help, thank you for your time!

Formatting md5sum differently?

I need to find the md5sum of files recursively and list these files alphabetically. However, in my final output I don't want the sum to actually show up. For example if I issue:
find -not -empty -type f -exec md5sum "{}" \;
I get this:
0df8724ef24b15e54cc9a26e7679bb90 ./doc1.txt
d453430ce039863e242365eecaad7888 ./doc2.txt
53b2e8ae1dfaeb64ce894f75dd6b957c ./test.sh~
1ba03849883277c3c315d5132d10d6f0 ./md5file.txt
6971b4dbbd6b5b8d1eefbadc0ecd1382 ./test.sh
is there a simple way make this command to show only the files like:
./doc1.txt
./doc2.txt
./test.sh~
./md5file.txt
./test.sh
thx!
As Cyrus and Sriharsha say, simply using:
find -not -empty -type f
will give you the result you need.
Pass the output of find command to awk or cut.
find -not -empty -type f -exec md5sum "{}" \; | awk '{print $2}'
OR
Use sed if the filename contains spaces.
find -not -empty -type f -exec md5sum "{}" \; | sed 's/^[^ ]\+ \+//'

cronjob to remove files older than N days with special characters

I'm trying to create a job to delete files on a linux box older than X days. Pretty straightforward with:
find /path/to/files -mtime +X -exec rm {}\;
Problem is all my files have special characters b/c they are pictures from a webcam - most contain parenthesis so the above command fails with "no such file or directory".
Have you tried this:
find /path/to/files -mtime +X -exec rm '{}' \;
Or perhaps:
rm $(find /path/to/files -mtime +X);
Or even this method using xargs instead of -exec:
find /path/to/files -mtime +X | xargs rm -f;
Another twist on xargs is to use -print0 which will help the script differentiate between spaces in filenames & spaces between the returned list by using the ASCII null character as a file separator:
find /path/to/files -mtime +X -print0 | xargs -0 rm -f;
Or as man find explains under -print0:
This primary always evaluates to true. It prints the pathname of
the current file to standard output, followed by an ASCII NUL
character (character code 0).
I would also recommend adding the -maxdepth and -type flags to better control what the script does. So I would use this for a dry-run test:
find /path/to/files -maxdepth 1 -type f -mtime +1 -exec echo '{}' \;
The -maxdepth flag controls how many directories down the find will execute and -type will limit the search to files (aka: f) so the script is focused on files only. This will simply echo the results. Then when you are comfortable with it, change the echo to rm.
Does
find /path/to/files -mtime +X -print | tr '()' '?' | xargs rm -f
work?

Regular expression - Find ocurrences that has one string

Im trying to find all files modified during de last 24 hours in /var/www/vhost directory.
That is working ok with the find command, then, I want to filter the list because i don't want jpg files, jpeg files and so on.
Now i have this and it's working ok:
find /var/www/vhosts/ -ctime 0 -type f | grep -ve ".jpg$" | grep -ve ".jpeg"
I guess (and know) there's a better solution to my problem.
Any help?
change your find command itself to
find /var/www/vhosts/ -not \( -name "*.jpeg" -o -name "*.jpg" \) -ctime 0 -type f
You can do it all with one find command:
find /var/www/vhosts -ctime 0 -type f \! -iname \*.jpg \! -iname \*.jpeg
Use -regex and ! (negation):
find $DIR -regextype posix-extended ! -regex '.*\.(gif|jpg|pdf|png)$'

Resources