Is there a one-liner that will list all executables from $PATH in Bash?
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
This is not an answer, but it’s showing binary, a command which you could run
compgen -c
(assuming bash)
Other useful commands
compgen -a # will list all the aliases you could run. compgen -b # will list all the built-ins you could run. compgen -k # will list all the keywords you could run. compgen -A function # will list all the functions you could run. compgen -A function -abck # will list all the above in one go.
Method 2
With zsh:
whence -pm '*'
Or:
print -rC1 -- $commands
(note that for commands that appear in more than one component of $PATH, they will list only the first one).
If you want the commands without the full paths, and sorted for good measure:
print -rC1 -- ${(ko)commands}
(that is, get the keys of that associative array instead of the values).
Method 3
In any POSIX shell, without using any external command (assuming printf is built in, if not fall back to echo) except for the final sorting, and assuming that no executable name contains a newline:
{ set -f; IFS=:; for d in $PATH; do set +f; [ -n "$d" ] || d=.; for f in "$d"/.[!.]* "$d"/..?* "$d"/*; do [ -f "$f" ] && [ -x "$f" ] && printf '%sn' "${f##*/}"; done; done; } | sort
If you have no empty component in $PATH (use . instead) nor components beginning with -, nor wildcard characters [?* in either PATH components or executable names, and no executables beginning with ., you can simplify this to:
{ IFS=:; for d in $PATH; do for f in $d/*; do [ -f $f ] && [ -x $f ] && echo ${f##*/}; done; done; } | sort
Using POSIX find and sed:
{ IFS=:; set -f; find -H $PATH -prune -type f -perm -100 -print; } | sed 's!.*/!!' | sort
If you’re willing to list the rare non-executable file or non-regular file in the path, there’s a much simpler way:
{ IFS=:; ls -H $PATH; } | sort
This skips dot files; if you need them, add the -A flag to ls if yours has it, or if you want to stick to POSIX: ls -aH $PATH | grep -Fxv -e . -e ..
There are simpler solutions in bash and in zsh.
Method 4
How about this
find ${PATH//:/ } -maxdepth 1 -executable
The string substitution is used with Bash.
Method 5
I came up with this:
IFS=':';for i in $PATH; do test -d "$i" && find "$i" -maxdepth 1 -executable -type f -exec basename {} ;; done
EDIT:
It seems that this is the only command that don’t trigger SELinux alert while reading some of the files in bin directory by apache user.
Method 6
If you can run Python 2 in your shell, the following (ridiculously long) one-liner can be used as well:
python2 -c 'import os;import sys;output = lambda(x) : sys.stdout.write(x + "n"); paths = os.environ["PATH"].split(":") ; listdir = lambda(p) : os.listdir(p) if os.path.isdir(p) else [ ] ; isfile = lambda(x) : True if os.path.isfile(os.path.join(x[0],x[1])) else False ; isexe = lambda(x) : True if os.access(os.path.join(x[0],x[1]), os.X_OK) else False ; map(output,[ os.path.join(p,f) for p in paths for f in listdir(p) if isfile((p,f)) and isexe((p,f)) ])'
This was mostly a fun exercise for myself to see if it could be done using one line of Python code without resorting to using the exec function. In a more readable form, and with some comments, the code looks like this:
import os
import sys
# This is just to have a function to output something on the screen.
# I'm using Python 2.7 in which 'print' is not a function and cannot
# be used in the 'map' function.
output = lambda(x) : sys.stdout.write(x + "n")
# Get a list of the components in the PATH environment variable. Will
# abort the program is PATH doesn't exist
paths = os.environ["PATH"].split(":")
# os.listdir raises an error is something is not a path so I'm creating
# a small function that only executes it if 'p' is a directory
listdir = lambda(p) : os.listdir(p) if os.path.isdir(p) else [ ]
# Checks if the path specified by x[0] and x[1] is a file
isfile = lambda(x) : True if os.path.isfile(os.path.join(x[0],x[1])) else False
# Checks if the path specified by x[0] and x[1] has the executable flag set
isexe = lambda(x) : True if os.access(os.path.join(x[0],x[1]), os.X_OK) else False
# Here, I'm using a list comprehension to build a list of all executable files
# in the PATH, and abusing the map function to write every name in the resulting
# list to the screen.
map(output, [ os.path.join(p,f) for p in paths for f in listdir(p) if isfile((p,f)) and isexe((p,f)) ])
Method 7
#!/usr/bin/env python
import os
from os.path import expanduser, isdir, join, pathsep
def list_executables():
paths = os.environ["PATH"].split(pathsep)
executables = []
for path in filter(isdir, paths):
for file_ in os.listdir(path):
if os.access(join(path, file_), os.X_OK):
executables.append(file_)
return executables
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0