213

How can I find only the executable files under a certain directory in Linux?

Will
  • 403
  • 1
  • 4
  • 12
HaiYuan Zhang
  • 3,957
  • 8
  • 33
  • 33
  • Here is a kind of BASH script, it is not-bad is what I can say :) http://stackoverflow.com/a/20209457/2067125 – AjayKumarBasuthkar Mar 26 '14 at 07:49
  • What about using the standard [`file` command](http://en.wikipedia.org/wiki/File_%28command%29)? – Breakthrough Dec 08 '14 at 14:22
  • 5
    For anyone wanting to do this on a **Mac** (tested on OS X 10.9.5): `ls -l | egrep '^[^d]..x..x..x.*$'` The above will list all executables (for all/user and group) in the current directory. *Note*: The `-executable` option does not work on a Mac hence the above workaround. – techfoobar Dec 08 '14 at 14:28
  • Also relevant: [Unix find: search for executable files](http://stackoverflow.com/questions/4458120/unix-find-search-for-executable-files) – Slothworks Aug 14 '15 at 06:10
  • 1
    @techfoobar: The question is ambiguous: Does it mean files that contain executable code, or does it mean files that have executable permission?  But even if we assume that executable permission is what is wanted (as the majority of the responses seem to), the question doesn't say **world-executable**.  Your solution will find files (and also fifos, sockets, symlinks, etc.) that have world execute permission, but not 750 (`-rwxr-x---`), which is still executable to some users. – G-Man Says 'Reinstate Monica' Feb 20 '16 at 03:06

8 Answers8

204

Checking for executable files can be done with -perm (not recommended) or -executable (recommended, as it takes ACL into account). To use the -executable option:

find DIR -executable

If you want to find only executable files and not searchable directories, combine with -type f:

find DIR -executable -type f
knittl
  • 3,962
  • 2
  • 18
  • 18
  • This will return files with the execute turned on only. A more thorough analysis would check for a shebang line or whether the file is binary –  Sep 10 '09 at 12:04
  • 26
    a shebang doesn’t mean they’re executable. it tells us only which interpreter to use. and by linux definition “executable files” are files with the executable (x) bit set – knittl Sep 10 '09 at 12:09
  • 3
    What version of find supports that type for -type? man find lists b, c, d, p, f, l, s and D on my system. – innaM Sep 10 '09 at 15:51
  • 2
    Same here, my find doesn't have a `-type x` either. – davr Sep 10 '09 at 17:17
  • For some reason I always think that "-type x" will work too. I can only imagine it was available on some flavour of Unix I used once. – David Webb Sep 21 '09 at 10:39
  • @dave: glad to hear i’m not the only one :) – knittl Sep 23 '09 at 09:23
  • 7
    If you have an old version of find (probably before 4.3.8) which lacks -executable use find . -perm /u=x,g=x,o=x. – Ludwig Weinzierl May 14 '10 at 19:06
  • 6
    -executable isn't at all portable and should be avoided – Good Person Oct 26 '12 at 15:54
  • 14
    `find: invalid predicate -executable'` on RHEL – SSH This May 17 '13 at 20:57
  • How about not executable? Seems like a good thing to add here... – Dan Bolser May 02 '19 at 14:54
  • 1
    @DanBolser that's as simple as `find -not -executable` (optionally with `-type f`, depending on whether you want to only include files in the result) – knittl May 02 '19 at 15:08
  • Thanks @knittl, worth editing the answer? – Dan Bolser May 03 '19 at 16:13
  • @DanBolser the discussion probably takes longer than actually updating the answer, but I think the answer is complete as it stands now. The OP was specfically about finding files which are executable, not about excluding them. I expect people to read the [find man page](https://linux.die.net/man/1/find) to some extent and they will find the basic `-not` operator there. – knittl May 03 '19 at 16:25
  • I can't edit it. I've been using find for years, but -executeable and -not are both new to me (just saying ;-) – Dan Bolser May 04 '19 at 19:08
  • It seems that if the `` is not present, then the directory is `.` by default. Is that correct? – pmor Apr 17 '23 at 11:51
  • @pmor For GNU find, yes, it defaults to `.`. On macOS the starting-point is mandatory. – knittl Apr 17 '23 at 21:13
42

Use the find's -perm option. This will find files in the current directory that are either executable by their owner, by group members or by others:

find . -perm /u=x,g=x,o=x

Edit:

I just found another option that is present at least in GNU find 4.4.0:

find . -executable

This should work even better because ACLs are also considered.

innaM
  • 10,192
  • 5
  • 42
  • 52
40

I know the question specifically mentions Linux, but since it's the first result on Google, I just wanted to add the answer I was looking for (for example if you are - like me at the moment - forced by your employer to use a non GNU/Linux system).

Tested on macOS 10.12.5

find . -perm +111 -type f
friederbluemle
  • 982
  • 1
  • 8
  • 16
8

I have another approach, in case what you really want is just to do something with executable files--and not necessarily to actually force find to filter itself:

for i in `find -type f`; do [ -x $i ] && echo "$i is executable"; done

I prefer this because it doesn't rely on -executable which is platform specific; and it doesn't rely on -perm which is a bit arcane, a bit platform specific, and as written above requires the file to be executable for everyone (not just you).

The -type f is important because in *nix directories have to be executable to be traversable, and the more of the query is in the find command, the more memory efficient your command will be.

Anyhow, just offering another approach, since *nix is the land of a billion approaches.

Mark McKenna
  • 216
  • 2
  • 2
  • (0) Which do you prefer, arcane and correct or intuitive and flawed?  I prefer correct.  (1) [innaM’s answer](http://superuser.com/a/39100/150988), featuring `find -perm`, finds files that have *any* execute permission bit set.  (2) By contrast, this answer finds only files for which the current user has execute permission.  Granted, that might be what the OP wants, but it’s unclear.  … (Cont’d) – Scott - Слава Україні Apr 24 '16 at 04:36
  • (Cont’d) …  (3) For clarity, you might want to change `\`…\`` to `$(…)` — see [this](http://unix.stackexchange.com/q/5778/23408), [this](http://unix.stackexchange.com/q/147838/23408), and [this](http://unix.stackexchange.com/q/104119/23408).  (4) But don’t do `for i in $(find …); do …`; it fails on filenames that contain space(s).  Instead, do `find … -exec …`.  (5) And, when you do work with shell variables, always quote them (in double quotes) unless you have a good reason not to, and you’re sure you know what you’re doing. – Scott - Слава Україні Apr 24 '16 at 04:36
  • @scott OK, I stand corrected :) I read the `-perm` argument as requiring all three, not one of them. Also, thank you for the input on protecting shell arguments, that's all stuff I wasn't aware of. – Mark McKenna Apr 25 '16 at 13:50
  • @MarkMcKenna you have a typo in there: `for i in `find . -type f`; do [ -x $i ] && echo "$i is executable"; done`; you are missing the part, which I use a dot(.) – Devy Aug 31 '16 at 20:07
  • @Scott `find -exec` seems to fail if what I want to do is `source` the found file, so I'm using `for... do...` – Jeff Feb 17 '21 at 23:51
5

A file marked executable need not be a executable or loadable file or object.

Here is what I use:

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
  • 2
    What does this do? – DerMike Jan 14 '15 at 08:04
  • @DerMike, It is one of the ways to find executable in current directory, including .so files, even if a file is not marked executable it can discover. – AjayKumarBasuthkar Jan 14 '15 at 21:59
  • Well, I mean, _how_ does it do that? – DerMike Jan 15 '15 at 10:05
  • It reads from the header of the file to discover, every binary file or script file has header. – AjayKumarBasuthkar Jan 15 '15 at 13:44
  • As far as I know, `-name "*"` has no effect on `find` — it normally finds all files that are not eliminated by tests. – G-Man Says 'Reinstate Monica' Feb 20 '16 at 03:11
  • @AjayKumarBasuthkar you are aware this is NOT an answer to the question? the question was how to find executable files (=those that can be executed, = those w/ +x). not how to find all ELF, EXE and whatever-ocamlrun-is files. – nonchip Aug 19 '16 at 12:40
  • 2
    @nonchip I strongly disagree. @OP did not ask what files were set to executable/+x, but what files were actually executable. The definition of what that means is left to the reader, but I would not consider `portrait.png` executable, even with `a+x`, and I would consider `/usr/bin/grep` an executable, even if it was accidentally changed to miss the `x` flag. – Torque Mar 20 '20 at 10:16
  • @Torque but `portrait.png` can be executable by your logic, just get a Piet interpreter. and even if then executable means "can be run with `./`" (which requires `x`) just configure `binfmt_misc`. also pretty sure the grammar "only the executable files" implies "only the files which are executable", not files that are of the few (of the many executable formats out there) you deemed worthy. that would be "only ELF files", "only programs" or similar. and you didn't find `.app`,`.py`, `.lua`, `.sh`, all executables (even usually with `./` from bash), unlike `.so` and `.dll`. – nonchip Apr 07 '20 at 07:15
  • Those down voting the answer with or without verifying the functioning of the script, reflects their ability to reason, discover usefulness &/ learn, acknowledge our peers, knowledge & maturity. – AjayKumarBasuthkar Apr 21 '20 at 06:33
  • 2
    The downvotes you’ve gotten so far reflect the belief that you’re answering the wrong question with a skimpy explanation. I wonder why you consider ``.so`` files to be executable but not ``.o`` files, and why you consider OCaml scripts to be executable but not shell scripts (or Awk, Perl, Python, etc.). Also, your answer has a typo. But *THIS* downvote is for the snarky, abusive comment. – G-Man Says 'Reinstate Monica' Feb 18 '21 at 19:58
4

As a fan of the one liner...

find /usr/bin -executable -type f -print0 | xargs file | grep ASCII

Using 'xargs' to take the output from the find command (using print0 to ensure filenames with spaces are handled correctly). We now have a list of files that are executable and we provide them, one by one, as the parameter for the 'file' command. Then grep for the term ASCII to ignore binaries. Please substitute -executable in find command with what style you prefer (see earlier answers) or what works on your 'NIX OS

I required the above to find files with eval in scripts owned by root, so created the following to help find priv escalation weaknesses where root user runs scripts with unsafe parameters...

echo -n "+ Identifying script files owned by root that execute and have an eval in them..."
find /  -not \( -path /proc -prune \)  -type f -executable -user root -exec grep -l eval {} \; -exec file {} \; | grep ASCII| cut -d ':' -f1 > $outputDir"/root_owned_scripts_with_eval.out" 2>/dev/null &
  • That won't work if the script contains non-ASCII characters. `file` reports the encoding, so a python script can be reported as `a /usr/bin/python script, UTF-8 Unicode text executable`. `find ... | xargs file -b | grep -v '^ELF'` could work better to spot the non-binaries. – xenoid Jul 12 '17 at 19:34
1

I created a function in ~/.bashrc tonight to find executable files not in the system path and not directories:

# Quickly locate executables not in the path
xlocate () {
    locate -0r "$1" | xargs -0 -I{} bash -c '[[ -x "$1" ]] && [[ ! -d "$1" ]] \
        &&  echo "executable: $1"'  _  {}
} # xlocate ()

The advantage is it will search three Linux distros and a Windows installation in under a second where the find command takes 15 minutes.

For example:

$ time xlocate llocate
executable: /bin/ntfsfallocate
executable: /home/rick/restore/mnt/e/bin/llocate
executable: /mnt/clone/bin/ntfsfallocate
executable: /mnt/clone/home/rick/restore/mnt/e/bin/llocate
executable: /mnt/clone/usr/bin/fallocate
executable: /mnt/e/bin/llocate
executable: /mnt/old/bin/ntfsfallocate
executable: /mnt/old/usr/bin/fallocate
executable: /usr/bin/fallocate

real    0m0.504s
user    0m0.487s
sys     0m0.018s

Or for a whole directory and all it's subs:

$ time xlocate /mnt/e/usr/local/bin/ | wc -l
65

real    0m0.741s
user    0m0.705s
sys     0m0.032s
  • This is the solution I will be using. Very time-efficient, and I like being able to put it in `~/.bashrc`. – bballdave025 May 01 '20 at 21:25
  • @bballdave025: That’s a red herring; *all* the answers could be put into ``.bashrc`` if you wanted to. – Scott - Слава Україні Feb 18 '21 at 00:33
  • Good point, @Scott , and one that shows that my comment is inaccurate. Thanks for pointing it out, so that others will know. Even so, because of the time-efficiency of this process, I choose to put this one in `~/.bashrc`, rather than the others. – bballdave025 Feb 19 '21 at 17:33
0

This finds the word executable in the output of "file". You could also grep for "ELF". This will find binary executable files if they have +x (executable bit) set or not. Here's my variation.

find . | while read a; do [[ $(file -b "$a" | grep executable) != "" ]] && echo $a; done
John
  • 121
  • 1