I want to find file types that are executable from the kernel's point of view. As far as I know all the executable files on Linux are ELF files. Thus I tried the following:
find * | file | grep ELF
However that doesn't work; does anybody have other ideas?
9 Answers 9
Later edit: only this one does what jan needs: thank you huygens;
find . -exec file {} \; | grep -i elf
-
find . -exec file {} \; | grep -i elf
is what I was looking for, thanks!JohnnyFromBF– JohnnyFromBF2012年06月05日 15:24:05 +00:00Commented Jun 5, 2012 at 15:24 -
2I think your first command doesn't work. It is searching for files with a name like "*elf *" (without taking into account the case). You want to grep the output just likeyou did in the second proposal.Huygens– Huygens2012年06月05日 15:26:38 +00:00Commented Jun 5, 2012 at 15:26
-
@huygens I tested it before I posted and it works. touch elf 1elf 1ELF2 elf2</code> ; my command will find all the elf related files;fromnaboo– fromnaboo2012年06月05日 15:28:44 +00:00Commented Jun 5, 2012 at 15:28
-
@huygens I tested it before I posted and it works. touch elf 1elf 1ELF2 elf2 ; my command will find all the elf related files (just like the grep); you got that error because you have copy pasted it (i think) and it has a blank space not needed, in the " " . but if I write "asteriskELFasterisk" in <code>, the html eats my asterisks!!!fromnaboo– fromnaboo2012年06月05日 15:35:05 +00:00Commented Jun 5, 2012 at 15:35
-
4This will find files that contain
"elf"
in their file name. I found that grepping for" elf "
was good enough for my application, but in the most general case a file named"this is not elf .txt"
would give a false positive.John McGehee– John McGehee2016年05月24日 20:22:10 +00:00Commented May 24, 2016 at 20:22
Alternate solution not using file
and readelf
, for those on limited (e.g. embedded) systems:
find $WHERE -type f -exec hexdump -n 4 -e '4/1 "%2x" " {}\n"' {} \; | grep ^7f454c46
Basically, we output first four bytes with hexdump
and use them as a signature. We can then grep all the files of type ELF using its signature 7f454c46
.
Or, since 7f
is the delete character, and 45
, 4c
, 46
bytes are E
, L
, F
characters respectively, we could also use:
find $WHERE -type f -exec hexdump -n 4 -e '4/1 "%1_u" " {}\n"' {} \; | grep ^delELF
Also, you can use head
instead of hexdump
in this case:
find $WHERE -type f -exec head -c 4 {} \; -exec echo " {}" \; | grep ^.ELF
-
The
grep
command could use the--text
flag. Without it, some file headers have characters that will putgrep
into binary mode--which will suppress all further matches with thegrep: (standard input): binary file matches
message.Jason Stewart– Jason Stewart2021年11月11日 23:36:43 +00:00Commented Nov 11, 2021 at 23:36 -
How about using
$'\x7FELF'
for the exact string to match?Adam Badura– Adam Badura2022年04月22日 08:42:08 +00:00Commented Apr 22, 2022 at 8:42
Like others, I want to answer too. My answer is based on using the find
utility too, but I have an idea, which is differ against other answers. It grounded on that fact, that the -exec
can be used as the search criteria too. Now, having this thing in mind, we can refactor all of the previous proposals to this one:
find /path -type f -exec sh -c "file {} | grep -Pi ': elf (32|64)-bit' > /dev/null" \; -print
I.e. we have moved the grep
into the -exec
.
What does this give to us, you may ask? We can use the flexibility of the -print
and others of the find
utility. For example, we can format an output on our taste, or use the -print0
and redirect an output to some script etc.
Assuming the original question refers to ELF files only (and not any other "executable from the kernel's point of view"), there is a shorter and, most likely, faster alternative to find
+ file
:
$ scanelf -R /SEARCH/PATH
TYPE FILE
ET_DYN /SEARCH/PATH/library.so
ET_EXEC /SEARCH/PATH/app1
ET_EXEC /SEARCH/PATH/app2
It recursively searches for ELF files, prints object file type and filepath for each.
Narrow the search down to only executable ELF files: scanelf -EET_EXEC -R /SEARCH/PATH
.
Suppress banner and type, keeping only filepaths: scanelf -EET_EXEC -RBF %F /SEARCH/PATH
.
-
2This command is available as part of the
pax-utils
package.Christian Hudon– Christian Hudon2022年07月05日 20:05:03 +00:00Commented Jul 5, 2022 at 20:05
Take a look on -executable
flag of find
.
-
3That's not quite what I want, I don't want files that are tagged as executable files but I want to find ELF files, files that are recognized as executable by the kernel.JohnnyFromBF– JohnnyFromBF2012年06月05日 15:21:33 +00:00Commented Jun 5, 2012 at 15:21
-
The flag executable match permissions (so directories too), see the man page:
Matches files which are executable and directories which are searchable (in a file name resolution sense).
Huygens– Huygens2012年06月05日 15:24:37 +00:00Commented Jun 5, 2012 at 15:24 -
2@Huygens: So directories are files (everything is a file on Unix), but to exclude them, just use
find -type f -executable
.user unknown– user unknown2012年06月05日 16:48:14 +00:00Commented Jun 5, 2012 at 16:48 -
2@Ian: But Shellscripts are executable by the kernel. Executable flag + appropriate shebang means executable file. Or flag + binary-elf, or flag + a.out, or flag + binfmt-patch.user unknown– user unknown2012年06月05日 16:49:53 +00:00Commented Jun 5, 2012 at 16:49
-
2@Huygens: No, you can execute shell scripts with exec-calls, see: en.wikipedia.org/wiki/Shebang_%28Unix%29 . If there is a shebang, only the rest of the script is executed by the interpreter. Since 1980.user unknown– user unknown2012年06月05日 17:19:08 +00:00Commented Jun 5, 2012 at 17:19
I would look for regular files first as binary executable are belonging to that type of files.
Then I would request for each regular file the mime type and if it matches application/x-executable then it is a binary executable files (that should match Linux executable files, Windows one for instance match application/x-dosexec).
find . -type f -print0 | xargs -0 -n 10 file -i | grep "application/x-executable"
Trying this command I found a discrepency with find . -type f -print0 | xargs -0 -n 10 file | grep -w ELF
. It seems that the command file
is buggy and detects ELF executable as ELF shared object. So even though the command is theoricaly correct, in practice it is incomplete.
So we have to look for ELF executables and shared objects but exclude all files with a name of *.so and .so.
find . -type f ! \( -name "*.so.*" -o -name "*.so" \) -print0 | xargs -0 -n 10 file -i | egrep "application\/x-sharedlib|application\/x-executable"
It is not probably perfect, but that's the pretty close.
-
Actually my first answer is not fully correct, as some binary executable files are detected by
file -i
as application/x-sharedlib and not application/x-executable.Huygens– Huygens2012年06月05日 15:50:37 +00:00Commented Jun 5, 2012 at 15:50 -
The binaries I sampled from my Mac are
application/octet-stream; charset=binary
, according to both the Mac'sfile
and thefile
on my Debian box. (Speaking of OS X, thefile
it includes uses-I
instead of-i
. Both accept--mime
, though.)Blacklight Shining– Blacklight Shining2014年02月26日 02:57:05 +00:00Commented Feb 26, 2014 at 2:57
I think this answers the original question if their intent was to find binary executable files by ensuring each match has an elf header.
It sort of pre-processes files based on type -executable
then runs the results through a separate shell that invokes readelf -l
which pipes to grep which silently matches on headers that are explicitly executable
. Anything that passes this test is passed to printf
for the output.
The pwd
bit outputs the full path.
find `pwd` -type f -executable -exec sh -c 'readelf -l "1ドル" 2>/dev/null | grep -qio 'executable' && printf "1ドル\n"' -- {} \;
find . -type f -executable -exec sh -c "[[ \"\$(head -c 4 -- \"\${1}\")\" == \$'\\x7FELF' ]]" -- \{\} \; -print
has the advantage that it doesn't "escape find
". Instead of the final -print
(or after it) you can add other filters or commands while still acting within the find
.
The part
-exec sh -c "[[ \"\$(head -c 4 -- \"\${1}\")\" == \$'\\x7FELF' ]]" -- \{\} \;
acts as a filter in the find
, discarding files that do not start with the ELF file marker.
I'm not sure if the
-type f -executable
part is truly needed, especially both conditions at once. But I guess in large trees it might be faster to discard the paths first based on the elementary properties, before trying to read them.
In my particular use case (that lead me here) I was trying to capture some basing ELF data of all executables generated by a build. However, the tree contained also other (non-ELF) executable files, like for example shell scripts. That caused readelf
to fail and break the find
. Adding the filter to discard non-ELF files first resolved the problem. For completeness, my full command was:
find . -type f -executable -exec sh -c "[[ \"\$(head -c 4 -- \"\${1}\")\" == \$'\\x7FELF' ]]" -- \{\} \; -print -exec readelf -d -- \{\} \;
find -type f -exec file {} \; | grep ELF | grep executable | cut -d: -f1
-
Doesn't work on all files/pathsAnthon– Anthon2015年07月12日 14:21:34 +00:00Commented Jul 12, 2015 at 14:21
binfmt_misc
you can run arbitrary files like classes, exes etc. en.wikipedia.org/wiki/Binfmt_miscbinfmt_misc
. Binary formats are as flexible as filesystems on Linux. By all means, find ELFs, but (a) you're not finding all executable files, (b) the ELFs you find aren't necessarily executable in practice. For instance, a SPARC64 ELF won't run on an x86.