Bash, Command Not Found

Command not found when running Bash script, but works when running command directly

By default, shell functions are only available in the shell they were defined in; they're not inherited by subprocesses. Your .bash_profile is only run by the login shell, not shells that run as subprocesses (e.g. to run scripts).

  • Option 1: In bash, you can run export -f letsencrypt_webfaction in the defining shell (i.e. in your .bash_profile), and it'll be inherited by subprocesses (provided they're also running bash).

  • Option 2: You can define the function in your .bashrc instead of .bash_profile, and since you run .bashrc from .bash_profile it'll get defined in all your bash shells.

  • Option 3: Just use the full command in the script. This would be my preference, since it makes the script more independent. Having a script depend on a shell function that's defined in a completely different place is fragile (as you're experiencing) and just a bit weird.

While I'm at it, here are some general scripting recommendations:

  • In most contexts, you should put double-quotes around variable references (and strings that contain variable references) to avoid weird effects from word splitting and wildcard expansion. The right side of an assignment is one place it's ok to leave them off (e.g. PATH=$PATH:$HOME/bin and PATH="$PATH:$HOME/bin" are both ok), but I tend to recommend using quotes everywhere as it's hard to keep track of where it's safe to leave them off and where it's dangerous. For the same reason, you should almost always use "$@" instead of $* (as in the letsencrypt_webfaction function).

    shellcheck.net is really good at spotting errors like this, so I recommend running your shell scripts through it and acting on its suggestions.

  • Using the function keyword to define a function is nonstandard; the standard syntax is to use () after the function name, like this:

    letsencrypt_webfaction() {
    PATH="$PATH:$GEM_HOME/bin" GEM_HOME="$HOME/.letsencrypt_webfaction/gems" RUBYLIB="$GEM_HOME/lib" ruby2.2 "$HOME/.letsencrypt_webfaction/gems/bin/letsencrypt_webfaction" "$@"
    }
  • The function I just gave still may not work right, since it (re)defines GEM_HOME after using it. The entire line gets parsed (and pre-existing variable definitions expanded), then the variables defined as prefixes to the command get included in the environment of the command. This means that the ruby script gets the updated value of GEM_HOME, but the updated values of PATH and RUBYLIB are based on whatever value GEM_HOME had when the function was run. I'm pretty sure this is not what you intended.

  • In the restart apache script, you use a relative path to the restart command. This will be evaluated relative to the working directory of the process that runs the script, not relative to the script's location. This could be anywhere.

Script gives if: command not found

I can solve this by using do eval "$HI". Of course, the problem is that if I use double quotes, then expansions are done at the first run. I don't want it to be expanded, but evaluated at every run.

EDIT: I got around this by using \$, or even better, using single quotes (this did mean I had to escape all the single quotes though).

EDIT 2: After consideration, I just decided to use functions without eval -- dealing with escaping was not worth it.

Bash script prints Command Not Found on empty lines

Make sure your first line is:

#!/bin/bash

Enter your path to bash if it is not /bin/bash


Try running:

dos2unix script.sh

That wil convert line endings, etc from Windows to unix format. i.e. it strips \r (CR) from line endings to change them from \r\n (CR+LF) to \n (LF).

More details about the dos2unix command (man page)


Another way to tell if your file is in dos/Win format:

cat scriptname.sh | sed 's/\r/<CR>/'

The output will look something like this:

#!/bin/sh<CR>
<CR>
echo Hello World<CR>
<CR>

This will output the entire file text with <CR> displayed for each \r character in the file.

How to handle command not found in bash

Insert this before your first echo line if you use bash >= 4.0:

command_not_found_handle() { echo "not found"; return 127; }

And then insert this after your last echo line to get rid of this function:

unset command_not_found_handle

Output, e.g.:


...RVM Version : not found
...Node Version : v4.2.6
...Ruby Version : ruby 2.3.1p112 (2016-04-26) [x86_64-linux-gnu]
...Bundler Version : not found
...Passenger Version: not found

zsh: command not found: ng

Possibly, on startup bash adds ng location to PATH, but zsh doesn't. You can check ~/.bashrc and ~/.bashprofile to see what is added to the PATH variable (all lines starting with export...), and copy these lines to ~/.zshrc file.



Related Topics



Leave a reply



Submit