218

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

5
  • Here is a kind of BASH script, it is not-bad is what I can say :) stackoverflow.com/a/20209457/2067125 Commented Mar 26, 2014 at 7:49
  • What about using the standard file command? Commented Dec 8, 2014 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
    Commented Dec 8, 2014 at 14:28
  • Also relevant: Unix find: search for executable files
    – Slothworks
    Commented Aug 14, 2015 at 6: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. Commented Feb 20, 2016 at 3:06

9 Answers 9

209

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
16
  • 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
    Commented Sep 10, 2009 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
    Commented Sep 10, 2009 at 15:51
  • 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. Commented May 14, 2010 at 19:06
  • 6
    -executable isn't at all portable and should be avoided Commented Oct 26, 2012 at 15:54
  • 14
    find: invalid predicate -executable' on RHEL
    – SSH This
    Commented May 17, 2013 at 20:57
43

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.

4
  • 3
    This only works on a newer version of find. The one that comes by default with CentOS gives the error find: invalid mode /u=x,g=x,o=x'`
    – davr
    Commented Sep 10, 2009 at 17:18
  • 12
    Then you should try the "-perm +" version which is now deprecated in GNU find: find . -perm +111"
    – innaM
    Commented Sep 10, 2009 at 19:32
  • Seems like -perm /111 may be the most portable version. Commented Apr 24, 2016 at 4:01
  • Works with mine busybox on arm
    – kyb
    Commented Nov 15, 2022 at 19:31
41

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.

This is tested on macOS 10.12.5:

find . -perm +111 -type f
4
  • 1
    Works in RHEL 5 too. Commented May 23, 2018 at 6:30
  • 2
    This is the only variant I could get working on OS X 10.14, thx
    – Justin
    Commented Jan 16, 2019 at 19:17
  • Needed this while using a busybox build of find. -executable did not work. -perm +111 is perfect.
    – jmcarter9t
    Commented Dec 17, 2019 at 17:31
  • from the man page -perm +mode This is no longer supported (and has been deprecated since 2005). Use -perm /mode instead.
    – rob
    Commented Jun 22, 2022 at 15:22
9

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).

. will start searching the current directory. This can be replaced with any directory path.

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.

5
  • (0) Which do you prefer, arcane and correct or intuitive and flawed?  I prefer correct.  (1) innaM’s answer, 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) Commented Apr 24, 2016 at 4:36
  • (Cont’d) …  (3) For clarity, you might want to change `…` to $(…) — see this, this, and this.  (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. Commented Apr 24, 2016 at 4: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. Commented Apr 25, 2016 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 <dir> part, which I use a dot(.)
    – Devy
    Commented Aug 31, 2016 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
    Commented Feb 17, 2021 at 23:51
4

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
10
  • 2
    What does this do?
    – DerMike
    Commented Jan 14, 2015 at 8: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. Commented Jan 14, 2015 at 21:59
  • Well, I mean, how does it do that?
    – DerMike
    Commented Jan 15, 2015 at 10:05
  • 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
    Commented Mar 20, 2020 at 10:16
  • 3
    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. Commented Feb 18, 2021 at 19:58
3

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 &
1
  • 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
    Commented Jul 12, 2017 at 19:34
2

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
3
  • This is the solution I will be using. Very time-efficient, and I like being able to put it in ~/.bashrc. Commented May 1, 2020 at 21:25
  • @bballdave025: That’s a red herring; all the answers could be put into .bashrc if you wanted to. Commented Feb 18, 2021 at 0: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. Commented Feb 19, 2021 at 17:33
2

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
-1

fd -tx

fd is a simple user friendly alternative to find written in rust.

You may need to install it as it is not included in POSIX standard.

https://github.com/sharkdp/fd

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .