Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.
# which mkdir
/bin/mkdir
# which mkdi
# 

How can I get the path of the e.g.: "mkdir"'s binary without knowing the name of the binary file? (command). So that which "mkdi" would output the "/bin/mkdir" too.

share|improve this question
add comment

7 Answers

up vote 2 down vote accepted

In zsh:

echo $path/mkdi*(N)

In other shells, for human consumption:

set -f; IFS=:
for x in $PATH; do set +f; ls $x/mkdi* 2>/dev/null; done
share|improve this answer
2  
@LanceBaynes, this is a better answer than mine. –  glenn jackman Jul 21 '11 at 2:00
    
Good, but not grep-like. no regex here. –  Philomath Jul 21 '11 at 15:28
    
@Philomath In ksh, bash and zsh, wildcards are regexps (with an unusual syntax). –  Gilles Jul 21 '11 at 15:40
    
~something like this –  LanceBaynes Jul 26 '11 at 6:08
add comment

locate

locate mkdi

Update: this will restrict the output to files in the $PATH

locate mkdi | 
while read filename; do 
  [[ ":$PATH:" == *:$(dirname $filename):* ]] && echo $filename
done
share|improve this answer
2  
locate searches the whole file-system based on a data-base, unlike which which searches the files in $PATH as per the current state. –  Philomath Jul 20 '11 at 18:59
    
On my system that returns thousands of files that happen to be in a project folder with that string fragment as part of the path. Not a replacement for which. –  Caleb Jul 20 '11 at 19:55
    
A slightly better way in practice is locate bin/mkdi. Still, it looks in public parts of the filesystem (or whatever updatedb indexes), without considering $PATH. –  Gilles Jul 20 '11 at 21:27
    
Note that if you want to search grep-like (regex), you have to pass -r or --regex to locate. It's still database based, though. –  Philomath Jul 21 '11 at 15:31
add comment

run-parts can do exactly that, given the right parameters. Here is a simple wrapper I wrote around it:

#!/bin/bash
# swhich - search the path (like which) but with support for regular expressions
# "swhich '.*ch$' '^wh'" to find all in path ending with 'ch' and all starting with 'wh'
set -f; IFS=:
for all in $PATH
  do
  set +f
  for each in "$@"
    do
    run-parts --list --regex "$each" "$all"
  done
done
share|improve this answer
add comment

If you're not sure of the executable you're looking for, you can also query the man database with the apropos command, for example apropos dir will list commands commonly used when working with directories, find the command you need, pass it to which as normal.

share|improve this answer
    
IF the executable has a manpage AND you have done makewhatis recently. –  Philomath Jul 20 '11 at 22:20
add comment

compgen is a BASH builtin that generates completions for a given string. The -c switch completes command names in the path:

$ compgen -c mkd
mkdirhier
mkdir
mkdiskimage
mkdir

Note: mkdir is on here twice because it's in both /bin and /usr/bin on my system.

Programmable completion is cool. It will let you do things like this:

$ shopt -s progcomp; complete -c which # set up progcomp
$ which mkd<ALT-*>
$ which mkdir mkdirhier mkdiskimage

...which may be closer to what you're looking for.

share|improve this answer
add comment

Here's yet another way of getting the binary path (if the prefix is known) by using printf and file name globbing in Bash.

mywhich() (
  bin="$1"
  PATH="${PATH// /\\ }"  # escape spaces
  #eval 'echo "$PATH"'
  #printf '%s\n' "printf '%s\n' ${PATH//://${bin}* }/${bin}*" | bash -s -f -O nullglob --
  result="$(printf '%s\n' "printf '%s\n' ${PATH//://${bin}* }/${bin}*" | bash -s +f -O nullglob --)"
  [[ -n "$result" ]] && printf '%s\n' "$result" && exit 0 || exit 1
)

mywhich mkdi
share|improve this answer
add comment

The following approach lists all full paths to the matched binaries using only Bash builtins:

# mywhich version 2
mywhich() ( # using a subshell the parent shell is not affected by set & shopt, ...
  bin="$1"
  set +f
  shopt -s nullglob
  IFS=':' read -a array <<<"$PATH"
  IFS=""
  result="$( printf '%s\n' ${array[@]/%//${bin}*} )"
  [[ -n "$result" ]] && printf '%s\n' "$result" && exit 0 || exit 1
)

mywhich mkdi
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.