Bash: Why can't I assign an absolute path to a variable? - linux

I am trying to assign an absolute path to a variable in Bash:
#!/bin/bash
DIR= "/home/foobar"
echo "$DIR/test"
The output:
./test.sh: line 2: /home/foobar: Is a directory
/test
I don't understand what is happening there, please help me.

Remove the space before "/home/foobar":
#!/bin/bash
DIR="/home/foobar"
echo "$DIR/test"

Try in another shell.
#!/bin/sh
DIR='/home/foobar'
echo "$DIR/test"
Or if you want to check if the variable is getting initialized or not using this.
#!/bin/sh
DIR='/home/foobar'
[ -z "$DIR" ] && echo "Variable not declared" && exit
echo "$DIR/test"

The general syntax is
[ assignment=value ... ] command arguments
so you are doing an assignment of DIR= and running the command /home/foobar -- which of course isn't a valid command, but a directory; hence the error message.
Try this:
DIR=/home/foobar bash -c 'echo "DIR is \"$DIR\""' # DIR is "/home/foobar"
echo "done. DIR is now \"$DIR\"" # DIR is now ""
and you will see that DIR is assigned only during the first command, then lost.
To set it for the remainder of your script, you can do
DIR=/home/foobar
echo "DIR is now $DIR"
and if you want to expose it to child processes, you can add an export:
DIR=/home/foobar
bash -c 'echo "Before export: DIR is \"$DIR\""' # DIR is ""
export DIR
bash -c 'echo "After export: DIR is \"$DIR\""' # DIR is "/home/foobar"

Related

Newbie: Script to change directories

The following is a snippet of a larger script I'm attempting. I just want this part to recognize the argument is a directory and then cd to that directory: i.e ./larj /etc.
#!/bin/ksh
# Filename: larj.sh
if [ $# -gt 1 ]; then
echo "0 or 1 arguments allowed."
exit
fi
if [ -f "$1" ]; then
echo "directory only."
exit
else
if [ -d "$1" ]; then
cd $1
fi
fi
When I run the script with /etc as the argument, it appears nothing happens; it stays in the same directory with no error.
Anyone have any suggestions how to get it to change directories?
Thanks
The cd is taking place within the script's shell.
When the script ends, it's shell exits, and you return to the directory before running the script. In order to change the directory you can
mkdir testdir
. ./your_script.sh testdir
At the end of the script you will be moved at directory testdir.
The problem why you cd can't work is that cd executes in the sub-shell when you execute the script as ./larj /etc. So when you execute the script, it changes the working directory of the subshell and has no impact on the current shell.
So you can execute it as . ./larj /etc.
Refer to Why doesn't “cd” work in a bash shell script?.

Basic Bash backup script

I'm still learning how to program in bash and for practice i'm trying to do a "backup script" (quotes because I know this isn't a proper backup) here is the code:
#|/bin/bash
sudo mkdir /home/lucas/bkp
echo "Type the path for the directory you want do save"
read directory
if [-d $directory]; then
sudo cp -R $directory /home/lucas/bkp/
else
echo "Path not found"
fi
But I get an error saying the path saved on variable does not exists and doing the same commands by "hand", directly on the shell everything is fine. Here is the error:
lucas#lucas-Linux:~$ sudo sh ./ex.sh
Type the path for the directory you want do save
/home/lucas/git/
./ex.sh: 7: ./ex.sh: [-d: not found
Path not found
You need to put spaces in your condition, like this :
if [ -d $directory ]; then

find out if a command is included in folders of environment variable PATH

I cannot find out how to see if a command is included in folders of environment variable PATH. I tried the command:
$type -t $command
but it doesn't work.
Can anyone help me?
This should work:
if [[ $(type -p command) ]]; then
echo "Found"
else
echo "Not Found"
fi
You can use -t too (See exceptions at bottom.).
Or (only testing the exit status with type):
if type command >& /dev/null; then
echo "Found"
else
echo "Not Found"
fi
Note: See exceptions at bottom.
Another solution (using hash):
if [[ ! $(hash command 2>&1) ]]; then
echo "Found"
else
echo "Not Found"
fi
Note: See exceptions at bottom.
Exceptions:
type command
type help
hash command
hash help
type -t command
type -t help
command and help are bash built-ins, they are not in any path in PATH environment variable. So the other methods except the first one (with -p option) will Print out Found for bash built-in commands which are not in any path in environment PATH variable.
Better use the first method (with -p option) if you only want to check if it's located in the paths in PATH environment variable.
Or if you want to use type -t then change the if statement like this:
if [[ $(type -t command) == file ]]; then
Do you mean looking at your path? Similar to:
$ set | grep PATH
Oh, now I understand. Checking for an executable in the path is fairly easy. I usually use something like the following:
## test for exe in PATH or exit
exevar="$(which exe 2>/dev/null)"
[ x = x$exevar ] && { echo "'exe' not in path"; exit 1; }
## exe in path, continue
echo "exevar = $exevar"
or use type -p to eliminate the call to which
## test for exe in PATH or exit
exevar="$(type -p exe 2>/dev/null)"
[ x = x$exevar ] && { echo "'exe' not in path"; exit 1; }
## exe in path, continue
echo "exevar = $exevar"

Bash file shows "ln: command not found"

I'm trying to create a bash script to setup my development environment. The script is running as root but I get the error line 11: ln: command not found
#!/bin/bash
#Require script to run as root - doesn't work - syntax error in conditional expression: unexpected token `;'
#if [[ $(/usr/bin/id -u) -ne 0]]; then
# echo "Script must be run as root";
# exit;
#fi
#PHPMyAdmin
PATH="/etc/apache2/sites-available/phpmyadmin.local";
if [ ! -a PATH ]; then
ln -s /home/user/Ubuntu\ One/htdocs/vhosts/phpmyadmin.local PATH;
a2ensite phpmyadmin.local;
fi
PATH=...
Congratulations, you've clobbered how the shell finds commands. Don't do that.
PATH tells the shell where to look for commands. In your case, it looks for ln somewhere in /etc and predictably doesn't find it there.
You should use a different name.

Bash script function call error

I am writing my first Bash script and am running into a syntax issue with a function call.
Specifically, I want to invoke my script like so:
sh myscript.sh -d=<abc>
Where <abc> is the name of a specific directory inside of a fixed parent directory (~/app/dropzone). If the child <abc> directory doesn't exist, I want the script to create it before going to that directory. If the user doesn't invoke the script with a -d argument at all, I want the script to exist with a simple usage message. Here's my best attempt at the script so far:
#!/bin/bash
dropzone="~/app/dropzone"
# If the directory the script user specified exists, overwrite dropzone value with full path
# to directory. If the directory doesn't exist, first create it. If user failed to specify
# -d=<someDirName>, exit the script with a usage statement.
validate_args() {
args=$(getopt d: "$*")
set -- $args
dir=$2
if [ "$dir" ]
then
if [ ! -d "${dropzone}/targets/$dir" ]
then
mkdir ${dropzone}/targets/$dir
fi
dropzone=${dropzone}/targets/$dir
else
usage
fi
}
usage() {
echo "Usage: $0" >&2
exit 1
}
# Validate script arguments.
validate_args $1
# Go to the dropzone directory.
cd dropzone
echo "Arrived at dropzone $dropzone."
# The script will now do other stuff, now that we're in the "dropzone".
# ...etc.
When I try running this I get the following error:
myUser#myMachine:~/app/scripts$ sh myscript.sh -dyoyo
mkdir: cannot create directory `/home/myUser/app/dropzone/targets/yoyo': No such file or directory
myscript.sh: 33: cd: can't cd to dropzone
Arrived at dropzone /home/myUser/app/dropzone/targets/yoyo.
Where am I going wrong, and is my general approach even correct? Thanks in advance!
Move the function definitions to the top of the script (below the hash-bang). bash is objecting to the undefined (at that point) call to validate_args. usage definition should precede the definition of validate_args.
There also should be spacing in the if tests "[ " and " ]".
if [ -d "$dropzone/targets/$1" ]
The getopt test for option d should be-:
if [ "$(getopt d "$1")" ]
Here is a version of validate_args that works for me.
I also had to change the drop zone as on my shell ~ wouldn't expand in mkdir command.
dropzone="/home/suspectus/app/dropzone"
validate_args() {
args=$(getopt d: "$*")
set -- $args
dir=$2
if [ "$dir" ]
then
if [ ! -d "${dropzone}/targets/$dir" ]
then
mkdir ${dropzone}/targets/$dir
fi
dropzone=${dropzone}/targets/$dir
else
usage
fi
}
To pass in all args use $* as parameter -:
validate_args $*
And finally call the script like this for getopt to parse correctly-:
myscript.sh -d dir_name
When invoked, a function is indistinguishable from a command — so you don't use parentheses:
validate_args($1) # Wrong
validate_args $1 # Right
Additionally, as suspectus points out in his answer, functions must be defined before they are invoked. You can see this with the script:
usage
usage()
{
echo "Usage: $0" >&2
exit 1
}
which will report usage: command not found assuming you don't have a command or function called usage available. Place the invocation after the function definition and it will work fine.
Your chosen interface is not the standard Unix calling convention for commands. You'd normally use:
dropzone -d subdir
rather than
dropzone -d=subdir
However, we can handle your chosen interface (but not using getopts, the built-in command interpreter, and maybe not using GNU getopt either, and certainly not using getopt as you tried to do so). Here's workable code supporting -d=subdir:
#!/bin/bash
dropzone="$HOME/app/dropzone/targets"
validate_args()
{
case "$1" in
(-d=*) dropzone="$dropzone/${1#-d=}"; mkdir -p $dropzone;;
(*) usage;;
esac
}
usage()
{
echo "Usage: $0 -d=dropzone" >&2
exit 1
}
# Validate script arguments.
validate_args $1
# Go to the dropzone directory.
cd $dropzone || exit 1
echo "Arrived at dropzone $dropzone."
# The script will now do other stuff, now that we're in the "dropzone".
# ...etc.
Note the cautious approach with the cd $dropzone || exit 1; if the cd fails, you definitely do not want to continue in the wrong directory.
Using the getopts built-in command interpreter:
#!/bin/bash
dropzone="$HOME/app/dropzone/targets"
usage()
{
echo "Usage: $0 -d dropzone" >&2
exit 1
}
while getopts d: opt
do
case "$opt" in
(d) dropzone="$dropzone/$OPTARG"; mkdir -p $dropzone;;
(*) usage;;
esac
done
shift $(($OPTIND - 1))
# Go to the dropzone directory.
cd $dropzone || exit 1
echo "Arrived at dropzone $dropzone."
# The script will now do other stuff, now that we're in the "dropzone".
# ...etc.

Resources