Find executable files, also those NOT marked executable - find

How to Find binary files with or without executable permissions?
I am working on a BASH script that would list in a path:
* Shared Object files,
* scripts, executable files,
* static libraries
It should not display intermediate files like .o (object files).

You can use:
find . -type f -print0 | xargs -0 -n 10 file -i | grep "application/x-executable"

The file program reports file type based on contents, so
file /bin/* | awk -F: '/executable/{print $1}'
reports potentially/actually executable files in /bin.

This worked for me & thought of sharing...
find ./ -type f -name "*" -not -name "*.o" -exec sh -c '
case "$(head -n 1 "$1")" in
?ELF*) exit 0;;
MZ*) exit 0;;
#!*/ocamlrun*)exit0;;
esac
exit 1
' sh {} \; -print

Related

Files With Spaces Are Treated As Seperate Files

How can I modify the script to not treat files with spaces as separate files?
thetime=`date +%Y-%m-%d_%H:%M:%S` #
for i in $(find . ! -name "*.filepart")
do
extn=${i##*.} # save the extension of the file
mv "$i" "${i%.*}"$(date "+_%Y-%m-%d_%H:%M:%S.${extn}")
done
mv: cannot stat ‘./user1/upload/Axle’: No such file or directory
mv: cannot stat ‘Assy’: No such file or directory
mv: cannot stat ‘Removal.doc’: No such file or directory
#find . ! -name "*.filepart"
#./user1/upload/Axle Assy Removal.doc
This won't work with files whose names contain whitespace:
for i in $(find . ! -name "*.filepart"); do # Fail
The following two methods will work for all file names:
Method 1: Use -execdir
find . -type f ! -name "*.filepart" -execdir sh -c 'f=$(basename "$1"); mv "./$f" "./${f%.*}$(date "+_%Y-%m-%d_%H:%M:%S")${f#${f%.*}}"' Mv {} \;
Method 2: Use -print0
find . -type f ! -name "*.filepart" -print0 | while IFS= read -r -d $'\0' file
do
d=$(dirname "$file")
f=${file#$d}
mv "$d$f" "$d${f%.*}$(date "+_%Y-%m-%d_%H:%M:%S")${f#${f%.*}}"
done
Further reading
How can I find and safely handle file names containing newlines, spaces or both?

Find and soft link without the parent path

So I have a find command as below which finds the libclntsh.so.* files in a directory instantclient.
find instantclient -type f -name "*libclntsh\.so\.[0-9]*\.[0-9]*"
This results in for e.g.,
instantclient/libclntsh.so.11.1
How do I now ln within instantclient directory, ln -s libclntsh.so.11.1 libclntsh.so all with a find command in combination with exec
I should mention here that I DO NOT want to cd into instantclient.
And this is for Alpine Linux.
Use the -execdir option. As per manual:
-execdir command {} ;
Like -exec, but the specified command is run from the subdirectory containing the matched file, which is not normally the directory in which you started find. This a much more secure method for invoking commands, as it avoids race conditions during resolution of the paths to the matched files.
So your command will be:
find instantclient -type f -name "*libclntsh\.so\.[0-9]*\.[0-9]*" -execdir ln -s {} libclntsh.so \;
EDIT:
Another solution
find instantclient -type f -name "*libclntsh\.so\.[0-9]*\.[0-9]*" | xargs -I {} sh -c 'ln -s $(basename {}) instantclient/libclntsh.so'

Files not available after running find command

I tried to rename files ending with ".txt" to ".abc" using the find command as below. Now the files are not available on my disk.
find ./ -type f -iname '*.txt' -exec sh -c 'mv "$0" "$1.abc"' {} \;
can someone explain me the above command in detail what is did with the files.
Is there any possibility to retrive those, if yes how ?
You used the wrong variable and most of the files cannot be retrieved.
find ./ -type f -iname '*.txt' -exec sh -c 'mv "$0" "$1.abc"' {} \;
will rename every .txt file to a file called .abc. So if you files named bar.txt and foo.txt it will rename bar.txt to .abc and then rename foo.txt to .abc which will overwrite the original contents of bar.txt. You cannot see the file because it is .abc and is hidden under a normal list. If you run 'ls -a' you will see a file named ".abc" which will have the contents of the last .txt file that was renamed.
I am not sure how to do exactly what you wanted but running
find ./ -type f -iname '*.txt' -exec sh -c 'mv "$0" "$0.abc"' {} \;
will rename each .txt file to a .txt.abc file. So you would have bar.txt.abc and foo.txt.abc
The explanation of rondo is correct.
But what are the solutions for your problem?
If you want to replace the suffix .txt with .abc you can use rename
You will have success, if you use rename and find like this:
find . -type f -iname '*.txt' -print0 | xargs -0 rename .txt .abc
For all files found by find like x.txt or a/b.txt the appropriate command will execute, e.g.
rename .txt .abc x.txt
rename .txt .abc a/b.txt
so x.txt -> x.abc, and a/b.txt -> a/b.abc
If you only want to add the suffix .abc to all files you can still use mv
find . -type f -iname '*.txt' -print0 | xargs -0 mv {} {}.abc
With xargs for each file the command mv is executed.
BTW: with the find option "-print0" and the xargs option "-0" the commands work also with filenames which includes spaces.

Query ragarding Solaris find command with -exec option

I want to create tar file with all the output files resulting from executing find command.
I tried the following command:
find . \(-name "*.log" -o -name "*.log.*" \) -mtime +7 -exec tar cvf test.tar.gz {} \;
But it is including only the last found file in the test.tar file. How to include all files in test.tar file?
Regards
Chaitanya
Use command line substitution:
tar cf test.tar $(find . \(-name "*.log" -o -name "*.log.*" \) -mtime +7)
What this does is run the command in $() and makes the output the command line arguments of the outer command.
This uses the more modern bash notation. If you are not using bash, you can also use backticks which should work with most shells:
tar cf test.tar `find . \(-name "*.log" -o -name "*.log.*" \) -mtime +7`
While backticks are more portable, the $() notation is easier if you need to nest command line substitution.
You want to pipe the file names found by find into tar.
find . \(-name "*.log" -o -name "*.log.*" \) -mtime +7 -exec tar cvf test.tar.gz {} \;
But it is including only the last found file in the test.tar file.
That's because for every file it finds it is running a new tar command that overwrites the tar file from the previous command.
You can make find batch the files together by changing the \; to a + but if there's more
files than can be listed at once, find will still run multiple commands, each overwriting the tar file from the previous one. You could pipe the output through xargs but it has the same issue of possibly running the command multiple times. The command line substitution recommended above is the safest way I know of to do it, ensuring that tar can only be called once -- but if too many files are found, it may give an error about the command line being too long.
This one should equally work:
find . -name "*.log" -o -name "*.log.*" -mtime +7 -exec tar cvf test.tar {} +
Note the "+" at the end vs "\;".
For a reliable way when a very large number of files will match the search:
find . -name "*.log" -o -name "*.log.*" -mtime +7 > /tmp/find.out
tar cvf test.tar -I /tmp/find.out

using find command to search for all files having some text pattern

I use following find command to find and show all files having the input text pattern.
find . -type f -print|xargs grep -n "pattern"
I have many project folders each of which has its own makefile named as 'Makefile'.(no file extension, just 'Makefile')
How do i use above command to search for a certain pattern only in the files named Makefile which are present in all my project folders?
-AD.
-print is not required (at least by GNU find implementation). -name argument allows to specify filename pattern. Hence the command would be:
find . -name Makefile | xargs grep pattern
If you have spaces or odd characters in your directory paths youll need to use the null-terminated method:
find . -name Makefile -print0 | xargs -0 grep pattern
find . -type f -name 'Makefile' | xargs egrep -n "pattern"
use egrep if you have very long paths
Duplicate of : this
You can avoid the use of xargs by using -exec:
find . -type f -name 'Makefile' -exec egrep -Hn "pattern" {} \;
-H on egrep to output the full path to the matching files.
grep -R "string" /path
Please find this link
http://rulariteducation.blogspot.in/2016/03/how-to-check-particluar-string-in-linux.html
you can use ff command i.e ff -p .format. For eg ff -p *.txt
Find big files occupying large disk space
we need to combine multiple command .
find . -type f | xargs du -sk | sort -n | tail;