Commands cannot be located after sourcing a bash script

I have a short bash script cdline that takes two arguments PATHS and LINE and changes directory to the respective LINE in PATHS:

#!/bin/bash
#command for changing directory to that in the given line...
#or that of the file in the given line

PATHS=$1
LINE=$2
PATH="$(echo "${PATHS}" | sed -n ${LINE}p)"
PATH="$(/home/gohomology/Scripts/pc_macros/file_system/getdir "${PATH}")"
cd ${PATH}

return 1

This calls getdir which echoes the given path if its a directory, or the directory that includes the file otherwise.

I know that when calling a bash script normally it creates a subshell, so trying to call the script normally wouldn’t do anything. As far as I understand, the solution for this should be sourcing the script, which one can do adding . or source before calling the script.

This indeed works for changing the directory, however, after doing so my terminal cannot find various commands such as ls or find, as demonstrated by the following result from my terminal emulator.

gohomology@gohomology:~/Desktop$ find . -name "example_file"
./example_dir/example_file

gohomology@gohomology:~/Desktop$ . cdline "$(!!)" 1
. cdline "$(find . -name "example_file")" 1

gohomology@gohomology:~/Desktop/example_dir$ ls
Command 'ls' is available in the following places
 * /bin/ls
 * /usr/bin/ls
The command could not be located because '/usr/bin:/bin' is not included in the PATH environment variable.
ls: command not found

gohomology@gohomology:~/Desktop/example_dir$ find . -name "example_file"
Command 'find' is available in the following places
 * /bin/find
 * /usr/bin/find
The command could not be located because '/bin:/usr/bin' is not included in the PATH environment variable.
find: command not found

The command cd still works after using cdline. I thought that the problem is that I’m stuck within a bash shell, which is why there’s return 1 at the end of cdline, but the problem is still existent.

I run bash 5.1.16 and gnome-terminal on Ubuntu 22.04.2.

Asked By: gohomology

||

The problem is that your script overrides your PATH environment variable:

PATH="$(echo "${PATHS}" | sed -n ${LINE}p)"
PATH="$(/home/gohomology/Scripts/pc_macros/file_system/getdir "${PATH}")"

If you look at the man pages of bash you’ll see what this variable is used for:

PATH

The search path for commands. It is a colon-separated list of
directories in which the shell looks for commands (see COMMAND
EXECUTION
below).

And then later under the Command Execution section:

If the name is neither a shell function nor a builtin, and contains no
slashes, bash searches each element of the PATH for a
directory containing an executable file by that name.

Since your PATH was overridden and now only includes your current working directory, bash doesn’t know where to look for the command.

The error you see clearly states the problem:

The command could not be located because '/usr/bin:/bin' is not included in the PATH environment variable.

The reason your cd succeeded is that cd is not an executable file that bash runs, it is a bash builtin command.

Bottom line, don’t use PATH for a variable name in the script, use a different name that’s not used by bash.

Answered By: aviro

PATH is a special variable that tells the shell where to look for commands, don’t use it as a temporary variable in your script.

from man bash.1

PATH

The search path for commands. It is a colon-separated list of directories in which the shell looks for commands (see COMMAND EXECUTION below). A zero-length (null) directory name in the value of PATH indicates the current directory. A null directory name may appear as two adjacent colons, or as an initial or trailing colon. The default path is system-dependent, and is set by the administrator who installs bash. A common value is “/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin”.

Answered By: memchr