So I was reading the book The Linux Command Line, and it says that commands are of four types:

(1) executable programs

(2) shell builtins

(3) shell functions (shell scripts)

(4) aliases

Then it says that in order to identify the type of a command, you can use the type command.

However, I noticed that the type command fails to distinguish between a shell function (shell script) and an executable command.

For example:

type cp
(will output: cp is /bin/cp)

type bzexe
(will output: bzexe is /bin/bzexe)

However, we all know that cp is an executable program and bzexe is a shell script.

So my question is now: what command can we use to differentiate between those two?

I do know about the file command, and it works fine. Is that the only solution?

  • 7
    A executable program is a file with the execute bit set on the file; if a shell script has that bit set, then to the os deems that file an executable program. That file actually doing something useful depend on other factors.
    – llua
    Dec 26, 2015 at 19:12
  • Does the book actually say "(3) shell functions (shell scripts)"? That's horribly wrong. If you use bash-completion in your interactive shells, you can see an example of a shell function by doing type -a _pids. Running shell scripts from the shell isn't special. You shouldn't normally try to source them instead of running them normally. When you run them normally, it doesn't matter what language they're written in. But yes, file is a good way to find out what kind of file something is if you're curious. Dec 27, 2015 at 13:51

2 Answers 2


A shell script is an executable program. That's why type says that it is one. A shell script is as much an executable command as a perl script, a python script, a native ELF executable, a cross-architecture executable being executed by Qemu through Linux's binfmt_misc mechanism, etc. Any executable file is an executable command, it doesn't matter what interpreter it uses.

As you can tell from my list of examples, the line between “a script” and “not a script” is fuzzy: any executable file that begins with a shebang is a script, but there are executable files that are neither native code nor scripts.

When you execute a program, what language it's written in is irrelevant. So it wouldn't make sense for type to tell you about it. The job of type is only to tell you what type of command it is from the point of view of the shell.

A shell script is not the same thing as a function. A function runs inside the shell, and can modify the shell's environment. A shell script is a separate program; this separate program may happen to be written in the same language as the program you're running right now, but that's just a coincidence.


The command you're wanting is file.

type /bin/bash
/bin/bash is /bin/bash

file /bin/bash
/bin/bash: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, stripped

type /bin/zcat
/bin/zcat is /bin/zcat

file /bin/zcat
/bin/zcat: POSIX shell script, ASCII text executable

EDIT: Sorry, I just read the last line of your post. file isn't the only option but it's probably the best. You could also use something like head to see if the file is plain text or binary but that's going to get messy fast :)

  • The best way is file "$(which cp)" so you can do it in one command without knowing the path.
    – Wildcard
    Dec 29, 2015 at 3:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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