views:

1053

answers:

8

Is it possible to get, using Bash, a list of commands starting with a certain string?
I would like to get what is printed hitting <tab> twice after typing the start of the command and, for example, store it inside a variable.

A: 

Iterate over the $PATH variable and do ls beginningofword* for each directory in the path?

To get it exactly equivalent, you would need to filter out only executable files and sort by name (should be pretty easy with ls flags and the sort command).

Oliver N.
A: 

What is listed when you hit are the binary files in your PATH that start with that string. So, if your PATH variable contains: PATH=/usr/local/bin:/usr/bin:/bin:/usr/games:/usr/lib/java/bin:/usr/lib/java/jre/bin:/usr/lib/qt/bin:/usr/share/texmf/bin:.

Bash will look in each of those directories to show you the suggestions once you hit . Thus, to get the list of commands starting with "ls" into a variable you could do: MYVAR=$(ls /usr/local/bin/ls* /usr/bin/ls* /bin/ls*) Naturally you could add all the other directories I haven't.

Eduardo
See my answer below for a quick way to parse $PATH (not my idea, I stole it)...
dmckee
+16  A: 

You should be able to use the compgen command, like so:

compgen -A builtin [YOUR STRING HERE]

For example, "compgen -A builtin l" returns

let 
local 
logout

You can use other keywords in place of "builtin" to get other types of completion. Builtin gives you shell builtin commands. "File" give you local filenames, etc.

Here's a list of actions (from the BASH man page for complete which uses compgen):

  alias      Alias names.  May also be specified as -a.
  arrayvar   Array variable names.
  binding    Readline key binding names.
  builtin    Names  of  shell builtin commands.  May also be specified as -b.
  command    Command names.  May also be specified as -c.
  directory  Directory names.  May also be specified as  -d.
  disabled   Names of disabled shell builtins.
  enabled    Names of enabled shell builtins.
  export     Names of exported shell variables.  May also be specified as -e.
  file       File names.  May also be specified as -f.
  function   Names of shell functions.
  group      Group names.  May also be specified as -g.
  helptopic  Help topics as accepted by the help builtin.
  hostname   Hostnames, as taken from the file specified by the HOSTFILE shell
                 variable.
  job        Job  names, if job control is active.  May also be specified as
                 -j.
  keyword    Shell reserved words.  May also be specified as -k.
  running    Names  of  running  jobs,  if  job  control  is active.
  service    Service names.  May also be specified as -s.
  setopt     Valid arguments for the -o option  to  the  set builtin.
  shopt      Shell  option  names  as  accepted by the shopt builtin.
  signal     Signal names.
  stopped    Names  of  stopped  jobs,  if  job  control  is active.
  user       User names.  May also be specified as -u.
  variable   Names  of  all  shell  variables.   May also be specified as -v.
JacobM
nice. i struggled with that and complete, but haven't been able to figure out how to use it. +1 :)
Johannes Schaub - litb
extremely useful indeed, and very nice answer. Thanks! (+1)
Paolo Tedesco
A: 

If you want exactly how bash would complete

COMPLETIONS=$(compgen -c "$WORD")

compgen completes using the same rules bash uses when tabbing.

Flame
+1  A: 

JacobM's answer is great. For doing it manually, i would use something like this:

echo $PATH  | tr : '\n' | 
 while read p; do 
  for i in $p/mod*; do
   [[ -x "$i" && -f "$i" ]] && echo $i     
  done
 done

The test before the output makes sure only executable, regular files are shown. The above shows all commands starting with mod.

Johannes Schaub - litb
A: 

Interesting, I didn't know about compgen. Here a script I've used to do it, which doesn't check for non-executables:

#!/bin/bash
echo $PATH | tr ':' '\0' | xargs -0 ls | grep "$@" | sort

Save that script somewhere in your $PATH (I named it findcmd), chmod u+w it, and then use it just like grep, passing your favorite options and pattern:

findcmd ^foo   # finds all commands beginning with foo
findcmd -i -E 'ba+r'  # finds all commands matching the pattern 'ba+r', case insensitively
Adam Rosenfield
A: 

Just for fun, another manual variant:

find -L $(echo $PATH | tr ":" " ") -name 'pattern' -type f -perm -001 -print

where pattern specifies the file name pattern you want to use. This will miss commands that are not globally executable, but which you have permission for.

[tested on Mac OS X]


Use the -or and -and flags to build a more comprehensive version of this command:

find -L $(echo $PATH | tr ":" " ") -name 'pattern' -type f
                                   \( \
                                       -perm -001 -or \
                                       \( -perm -100 -and -user $(whoami)\) \
                                   \) -print

will pick up files you have permission for by virtue of owning them. I don't see a general way to get all those you can execute by virtue of group affiliation without a lot more coding.

dmckee
+1  A: 

A fun way to do this is to hit M-* (Meta is usually left Alt).

As an example, type this:

$ lo

Then hit M-*:

$ loadkeys loadunimap local locale localedef locale-gen locate
  lockfile-create lockfile-remove lockfile-touch logd logger login
  logname logout logprof logrotate logsave look lorder losetup

You can read more about this in man 3 readline; it's a feature of the readline library.

Porges