1 This file is type.def, from which is created type.c.
2 It implements the builtin "type" in Bash.
4 Copyright (C) 1987-2011 Free Software Foundation, Inc.
6 This file is part of GNU Bash, the Bourne Again SHell.
8 Bash is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
13 Bash is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with Bash. If not, see <http://www.gnu.org/licenses/>.
24 $FUNCTION type_builtin
25 $SHORT_DOC type [-afptP] name [name ...]
26 Display information about command type.
28 For each NAME, indicate how it would be interpreted if used as a
32 -a display all locations containing an executable named NAME;
33 includes aliases, builtins, and functions, if and only if
34 the `-p' option is not also used
35 -f suppress shell function lookup
36 -P force a PATH search for each NAME, even if it is an alias,
37 builtin, or function, and returns the name of the disk file
38 that would be executed
39 -p returns either the name of the disk file that would be executed,
40 or nothing if `type -t NAME' would not return `file'.
41 -t output a single word which is one of `alias', `keyword',
42 `function', `builtin', `file' or `', if NAME is an alias, shell
43 reserved word, shell function, shell builtin, disk file, or not
47 NAME Command name to be interpreted.
50 Returns success if all of the NAMEs are found; fails if any are not found.
55 #include "../bashtypes.h"
56 #include "posixstat.h"
58 #if defined (HAVE_UNISTD_H)
63 #include "../bashansi.h"
64 #include "../bashintl.h"
67 #include "../findcmd.h"
68 #include "../hashcmd.h"
75 #include "bashgetopt.h"
77 extern int find_reserved_word __P((char *));
79 extern char *this_command_name;
80 extern int expand_aliases, posixly_correct;
82 /* For each word in LIST, find out what the shell is going to do with
83 it as a simple command. i.e., which file would this shell use to
84 execve, or if it is a builtin command, or an alias. Possible flag
86 -t Returns the "type" of the object, one of
87 `alias', `keyword', `function', `builtin',
90 -p Returns the pathname of the file if -type is
93 -a Returns all occurrences of words, whether they
94 be a filename in the path, alias, function,
97 -f Suppress shell function lookup, like `command'.
99 -P Force a path search even in the presence of other
114 int dflags, any_failed, opt;
118 return (EXECUTION_SUCCESS);
120 dflags = CDESC_SHORTDESC; /* default */
123 /* Handle the obsolescent `-type', `-path', and `-all' by prescanning
124 the arguments and converting those options to the form that
125 internal_getopt recognizes. Converts `--type', `--path', and `--all'
126 also. THIS SHOULD REALLY GO AWAY. */
127 for (this = list; this && this->word->word[0] == '-'; this = this->next)
129 char *flag = &(this->word->word[1]);
131 if (STREQ (flag, "type") || STREQ (flag, "-type"))
133 this->word->word[1] = 't';
134 this->word->word[2] = '\0';
136 else if (STREQ (flag, "path") || STREQ (flag, "-path"))
138 this->word->word[1] = 'p';
139 this->word->word[2] = '\0';
141 else if (STREQ (flag, "all") || STREQ (flag, "-all"))
143 this->word->word[1] = 'a';
144 this->word->word[2] = '\0';
148 reset_internal_getopt ();
149 while ((opt = internal_getopt (list, "afptP")) != -1)
157 dflags |= CDESC_NOFUNCS;
160 dflags |= CDESC_PATH_ONLY;
161 dflags &= ~(CDESC_TYPE|CDESC_SHORTDESC);
164 dflags |= CDESC_TYPE;
165 dflags &= ~(CDESC_PATH_ONLY|CDESC_SHORTDESC);
167 case 'P': /* shorthand for type -ap */
168 dflags |= (CDESC_PATH_ONLY|CDESC_FORCE_PATH);
169 dflags &= ~(CDESC_TYPE|CDESC_SHORTDESC);
182 found = describe_command (list->word->word, dflags);
184 if (!found && (dflags & (CDESC_PATH_ONLY|CDESC_TYPE)) == 0)
185 sh_notfound (list->word->word);
187 any_failed += found == 0;
191 opt = (any_failed == 0) ? EXECUTION_SUCCESS : EXECUTION_FAILURE;
192 return (sh_chkwrite (opt));
196 * Describe COMMAND as required by the type and command builtins.
198 * Behavior is controlled by DFLAGS. Flag values are
199 * CDESC_ALL print all descriptions of a command
200 * CDESC_SHORTDESC print the description for type and command -V
201 * CDESC_REUSABLE print in a format that may be reused as input
202 * CDESC_TYPE print the type for type -t
203 * CDESC_PATH_ONLY print the path for type -p
204 * CDESC_FORCE_PATH force a path search for type -P
205 * CDESC_NOFUNCS skip function lookup for type -f
206 * CDESC_ABSPATH convert to absolute path, no ./ prefix
208 * CDESC_ALL says whether or not to look for all occurrences of COMMAND, or
209 * return after finding it once.
212 describe_command (command, dflags)
216 int found, i, found_file, f, all;
223 all = (dflags & CDESC_ALL) != 0;
224 found = found_file = 0;
225 full_path = (char *)NULL;
228 /* Command is an alias? */
229 if (((dflags & CDESC_FORCE_PATH) == 0) && expand_aliases && (alias = find_alias (command)))
231 if (dflags & CDESC_TYPE)
233 else if (dflags & CDESC_SHORTDESC)
234 printf (_("%s is aliased to `%s'\n"), command, alias->value);
235 else if (dflags & CDESC_REUSABLE)
237 x = sh_single_quote (alias->value);
238 printf ("alias %s=%s\n", command, x);
249 /* Command is a shell reserved word? */
250 if (((dflags & CDESC_FORCE_PATH) == 0) && (i = find_reserved_word (command)) >= 0)
252 if (dflags & CDESC_TYPE)
254 else if (dflags & CDESC_SHORTDESC)
255 printf (_("%s is a shell keyword\n"), command);
256 else if (dflags & CDESC_REUSABLE)
257 printf ("%s\n", command);
265 /* Command is a function? */
266 if (((dflags & (CDESC_FORCE_PATH|CDESC_NOFUNCS)) == 0) && (func = find_function (command)))
268 if (dflags & CDESC_TYPE)
270 else if (dflags & CDESC_SHORTDESC)
274 printf (_("%s is a function\n"), command);
276 /* We're blowing away THE_PRINTED_COMMAND here... */
278 result = named_function_string (command, function_cell (func), FUNC_MULTILINE|FUNC_EXTERNAL);
279 printf ("%s\n", result);
281 else if (dflags & CDESC_REUSABLE)
282 printf ("%s\n", command);
290 /* Command is a builtin? */
291 if (((dflags & CDESC_FORCE_PATH) == 0) && find_shell_builtin (command))
293 if (dflags & CDESC_TYPE)
295 else if (dflags & CDESC_SHORTDESC)
296 printf (_("%s is a shell builtin\n"), command);
297 else if (dflags & CDESC_REUSABLE)
298 printf ("%s\n", command);
306 /* Command is a disk file? */
307 /* If the command name given is already an absolute command, just
308 check to see if it is executable. */
309 if (absolute_program (command))
311 f = file_status (command);
314 if (dflags & CDESC_TYPE)
316 else if (dflags & CDESC_SHORTDESC)
317 printf (_("%s is %s\n"), command, command);
318 else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY))
319 printf ("%s\n", command);
321 /* There's no use looking in the hash table or in $PATH,
322 because they're not consulted when an absolute program
328 /* If the user isn't doing "-a", then we might care about
329 whether the file is present in our hash table. */
330 if (all == 0 || (dflags & CDESC_FORCE_PATH))
332 if (full_path = phash_search (command))
334 if (dflags & CDESC_TYPE)
336 else if (dflags & CDESC_SHORTDESC)
337 printf (_("%s is hashed (%s)\n"), command, full_path);
338 else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY))
339 printf ("%s\n", full_path);
346 /* Now search through $PATH. */
350 full_path = find_user_command (command);
353 user_command_matches (command, FS_EXEC_ONLY, found_file);
354 /* XXX - should that be FS_EXEC_PREFERRED? */
359 /* If we found the command as itself by looking through $PATH, it
360 probably doesn't exist. Check whether or not the command is an
361 executable file. If it's not, don't report a match. This is
362 the default posix mode behavior */
363 if (STREQ (full_path, command) || posixly_correct)
365 f = file_status (full_path);
366 if ((f & FS_EXECABLE) == 0)
369 full_path = (char *)NULL;
373 else if (ABSPATH (full_path))
374 ; /* placeholder; don't need to do anything yet */
375 else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY|CDESC_SHORTDESC))
377 f = MP_DOCWD | ((dflags & CDESC_ABSPATH) ? MP_RMDOT : 0);
378 x = sh_makepath ((char *)NULL, full_path, f);
383 /* If we require a full path and don't have one, make one */
384 else if ((dflags & CDESC_ABSPATH) && ABSPATH (full_path) == 0)
385 full_path = sh_makepath ((char *)NULL, full_path, MP_DOCWD|MP_RMDOT);
390 if (dflags & CDESC_TYPE)
392 else if (dflags & CDESC_SHORTDESC)
393 printf (_("%s is %s\n"), command, full_path);
394 else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY))
395 printf ("%s\n", full_path);
398 full_path = (char *)NULL;