How can I check if a program exists from a Bash script?
How would I validate that a program exists, in a way that will either return an error and exit, or continue with the script? It seems like it should be easy, but it’s been stumping me.
What is a «program»? Does it include functions and aliases? which returns true for these. type without arguments will additionally return true for reserved words and shell builtins. If «program» means «excutable in $PATH «, then see this answer.
@TomHale It depends on which implementation of which you are using; which is not provided by Bash, but it is by e.g. Debian’s debianutils.
@jano Since the context is bash, type would be preferable over which , since we know that it is available. Howeever, both type and which do not detect, whether a program exists, but whether is is found in the PATH. To see whether a program of a certain name «exists» in a file system, you would have to use find .
39 Answers 39
Answer
if ! command -v &> /dev/null then echo " could not be found" exit fi
For Bash specific environments:
hash # For regular commands. Or. type # To check built-ins and keywords
Explanation
Avoid which . Not only is it an external process you’re launching for doing very little (meaning builtins like hash , type or command are way cheaper), you can also rely on the builtins to actually do what you want, while the effects of external commands can easily vary from system to system.
- Many operating systems have a which that doesn’t even set an exit status, meaning the if which foo won’t even work there and will always report that foo exists, even if it doesn’t (note that some POSIX shells appear to do this for hash too).
- Many operating systems make which do custom and evil stuff like change the output or even hook into the package manager.
So, don’t use which . Instead use one of these:
command -v foo >/dev/null 2>&1 || < echo >&2 "I require foo but it's not installed. Aborting."; exit 1; >
type foo >/dev/null 2>&1 || < echo >&2 "I require foo but it's not installed. Aborting."; exit 1; >
hash foo 2>/dev/null || < echo >&2 "I require foo but it's not installed. Aborting."; exit 1; >
(Minor side-note: some will suggest 2>&- is the same 2>/dev/null but shorter – this is untrue. 2>&- closes FD 2 which causes an error in the program when it tries to write to stderr, which is very different from successfully writing to it and discarding the output (and dangerous!))
If your hash bang is /bin/sh then you should care about what POSIX says. type and hash ‘s exit codes aren’t terribly well defined by POSIX, and hash is seen to exit successfully when the command doesn’t exist (haven’t seen this with type yet). command ‘s exit status is well defined by POSIX, so that one is probably the safest to use.
If your script uses bash though, POSIX rules don’t really matter anymore and both type and hash become perfectly safe to use. type now has a -P to search just the PATH and hash has the side-effect that the command’s location will be hashed (for faster lookup next time you use it), which is usually a good thing since you probably check for its existence in order to actually use it.
As a simple example, here’s a function that runs gdate if it exists, otherwise date :
gnudate() < if hash gdate 2>/dev/null; then gdate "$@" else date "$@" fi >
Alternative with a complete feature set
You can use scripts-common to reach your need.
To check if something is installed, you can do:
checkBin || errorMessage "This tool requires . Install it please, and then run this tool again."
Searching for executable files
Is there a way to search and delete all executables files within folder if there is no extension? e.g Let’s suppose I have 4 files with .ubu extension and the following bash does the job I’m asking for:
e.g_2 Now let’s suppose I have 4 but there is no extension at all, something like: test test_2 test_3 ( chmod +x on them) How do I delete those files?
3 Answers 3
If we’re talking about files with executable bit set, then find command has -executable test, and a -delete action.
find /DIR/EC/TORY -type f -executable -delete
find /DIR/EC/TORY -type f -executable -exec rm -f <> \;
To specifically delete all executable files in your home directory (not in sub-directories) and ask you whether you want to delete each file you can do something like
find ~ -type f -executable -maxdepth 0 -exec rm -i <> \;
-exec command ; Execute command; true if 0 status is returned. All following arguments to find are taken to be arguments to the command until an argument consisting of `;' is encountered. The string `<>' is replaced by the current file name being processed everywhere it occurs in the arguments to the command, not just in arguments where it is alone, as in some versions of find. Both of these constructions might need to be escaped (with a `\') or quoted to protect them from expansion by the shell. See the EXAMPLES sec‐ tion for examples of the use of the -exec option. The specified command is run once for each matched file. The command is exe‐ cuted in the starting directory. There are unavoidable secu‐ rity problems surrounding use of the -exec action; you should use the -execdir option instead. -exec command <> + This variant of the -exec action runs the specified command on the selected files, but the command line is built by appending each selected file name at the end; the total number of invoca‐ tions of the command will be much less than the number of matched files. The command line is built in much the same way that xargs builds its command lines. Only one instance of `<>' is allowed within the command. The command is executed in the starting directory.
How can I find only the executable files under a certain directory in Linux?
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: 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.
8 Answers 8
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:
If you want to find only executable files and not searchable directories, combine with -type f :
find DIR -executable -type f
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
What version of find supports that type for -type? man find lists b, c, d, p, f, l, s and D on my system.
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.
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:
I just found another option that is present at least in GNU find 4.4.0:
This should work even better because ACLs are also considered.
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’`
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
from the man page -perm +mode This is no longer supported (and has been deprecated since 2005). Use -perm /mode instead.
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.
(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)
(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.
@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.
@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
A file marked executable need not be a executable or loadable file or object.
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
@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.
@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.
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.
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 &