12

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?

George M
  • 13,589
  • 4
  • 43
  • 53
JohnnyFromBF
  • 3,476
  • 10
  • 32
  • 42
  • @Levon It shows me the usage help of file. Probably file can't handle the input of find. – JohnnyFromBF Jun 05 '12 at 15:19
  • 4
    Just a small side node, with `binfmt_misc` you can run arbitrary files like classes, exes etc. http://en.wikipedia.org/wiki/Binfmt_misc – Ulrich Dangel Jun 05 '12 at 15:35
  • @UlrichDangel: +1 for mentioning `binfmt_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. – Alexios Jun 05 '12 at 16:25
  • No. The a.out files are executable as well, and files marked executable like bashscripts with appropriate shebang. – user unknown Jun 05 '12 at 16:42
  • 1
    Why do I get negative votes on that question, idiots at work? – JohnnyFromBF Jun 05 '12 at 17:27
  • Maybe because you don't correct your statement about executable files, but in the comments we can read that you're only interested in binary-elf files? – user unknown Jun 06 '12 at 00:41
  • Yeah maybe, but well I'm far from beeing an expert, rather a unix beginner thus I mentioned that I was not sure if ELF was the only type of executables. It happens that a beginner can't post a question a 100% correct but rather vague just because he's a beginner. – JohnnyFromBF Jun 06 '12 at 07:46
  • 1
    Nobody expects you to be an expert when asking, but for question, to be useful for others, it should be selfcontained, and give all needed information. The reader shouldn't be forced to read all the spread comments. Users search for questions by keywords, phrases and decide to read it by the headline. If you don't work on your question to improve it, it is useless for others and should receive even more downvotes. If it is clarified in the question, what you're really looking for - mainly in the headline - it can be upvoted. A downvote is however locked until the question is edited. – user unknown Jun 06 '12 at 15:12
  • If you improve your question, so that most of the comments get obsolete, these comments can be deleted. This improves the question even further, since there is less noise to read. Think information / noise ratio. – user unknown Jun 06 '12 at 15:13

9 Answers9

18

Later edit: only this one does what jan needs: thank you huygens;

find . -exec file {} \; | grep -i elf

fromnaboo
  • 6,702
  • 2
  • 22
  • 13
  • `find . -exec file {} \; | grep -i elf` is what I was looking for, thanks! – JohnnyFromBF Jun 05 '12 at 15:24
  • 2
    I 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 Jun 05 '12 at 15:26
  • @huygens I tested it before I posted and it works. touch elf 1elf 1ELF2 elf2 ; my command will find all the elf related files; – fromnaboo Jun 05 '12 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 , the html eats my asterisks!!! – fromnaboo Jun 05 '12 at 15:35
  • If you do `cd /sbin; find . -iname "*elf*" -exec file {} \;` it will report no files :) however `cd /sbin; find . -exec file {} \; | grep -i elf` will report several. Hence my point is correct. The -iname option of find just check if the filename match the pattern. So if a ELF executable is called mkswap, you won't find it. PS: I've tried both `"*elf*"` and `*elf *"` and as I would expect no binaries are found in /sbin which is incorrect. – Huygens Jun 05 '12 at 15:36
  • @huygens : you are write, my mistake. I did not understand well what ian needed, at first. – fromnaboo Jun 05 '12 at 15:38
  • @fromnaboo no problem, you can edit and correct your post as the second part is correct. :) – Huygens Jun 05 '12 at 15:44
  • i edited it, thanks (my internet connection is crappy, that's why i double post) – fromnaboo Jun 05 '12 at 15:47
  • 2
    This 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 May 24 '16 at 20:22
7

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
Alex Che
  • 261
  • 2
  • 9
  • The `grep` command could use the `--text` flag. Without it, some file headers have characters that will put `grep` into binary mode--which will suppress all further matches with the `grep: (standard input): binary file matches` message. – Jason Stewart Nov 11 '21 at 23:36
  • How about using `$'\x7FELF'` for the exact string to match? – Adam Badura Apr 22 '22 at 08:42
3

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.

Serge Roussak
  • 319
  • 2
  • 11
2

Take a look on -executable flag of find.

  • 3
    That'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 Jun 05 '12 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 Jun 05 '12 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 Jun 05 '12 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 Jun 05 '12 at 16:49
  • @userunknown shell script aren't executable by the kernel. You need to run a shell and have the interpreter to execute them. As I understood Ian question, he is looking only for binary executable files. Thus `find -type f -executable` would not be correct as shell script would be reported. In addition if a binary does not have the x permission, this command would not detect it. Either it is wanted or not, both cases have different purpose. – Huygens Jun 05 '12 at 16:58
  • 2
    @Huygens: No, you can execute shell scripts with exec-calls, see: http://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 Jun 05 '12 at 17:19
  • @userunknown interesting, didn't know that. – Huygens Jun 06 '12 at 08:22
  • This is the way. – Whome Aug 30 '23 at 13:58
1

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.

Huygens
  • 8,985
  • 3
  • 31
  • 36
  • 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 Jun 05 '12 at 15:50
  • The binaries I sampled from my Mac are `application/octet-stream; charset=binary`, according to both the Mac's `file` and the `file` on my Debian box. (Speaking of OS X, the `file` it includes uses `-I` instead of `-i`. Both accept `--mime`, though.) – Blacklight Shining Feb 26 '14 at 02:57
1

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"' -- {} \;
noabody
  • 31
  • 3
1

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.

AleXoundOS
  • 284
  • 2
  • 12
0
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 -- \{\} \;
Adam Badura
  • 313
  • 1
  • 2
  • 7
-2
find -type f -exec file {} \; | grep ELF | grep executable | cut -d: -f1