I have a shell script named ‘teleport.sh’ like this:
if [ $1="1" ];
then
shift
mv "<a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="a682e6">[email protected]</a>" ~/lab/Sun
elif [ $1="2" ];
then
shift
mv "<a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="e1c5a1">[email protected]</a>" ~/lab/Moon
elif [ $1="3" ];
then
shift
mv "<a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="86a2c6">[email protected]</a>" ~/lab/Earth
fi
When I execute:
sh teleport.sh 2 testfile
This testfile is moved to the ~/lab/Sun directory, which confuses me a lot as I didn’t pass 1 or ‘1’ to that script.
What’s wrong here?
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
Using spaces fixes your problem.
if [ "$1" = 1 ];
then
shift
mv "<a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="567216">[email protected]</a>" ~/lab/Sun
elif [ "$1" = 2 ];
then
shift
mv "<a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="604420">[email protected]</a>" ~/lab/Moon
elif [ "$1" = 3 ];
then
shift
mv "<a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="537713">[email protected]</a>" ~/lab/Earth
fi
Though this is neater:
#!/bin/bash
action=$1
shift
files=("<a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="567216">[email protected]</a>")
case $action in
1) mv -- "${files[@]}" ~/lab/Sun ;;
2) mv -- "${files[@]}" ~/lab/Moon ;;
3) mv -- "${files[@]}" ~/lab/Earth ;;
esac
Method 2
First obvious thing is you should provide spaces between the arguments of [, test or [[:
if [ "$1" = 1 ];
When in Bash, using [[ ]] is recommended as it doesn’t do things unnecessary for conditional expression like word splitting and pathname expansion. Quoting around double-quotes is also not needed. A more readable operator == can also be used.
if [[ $1 == 1 ]];
Added note: If second operand also contains variables, quoting is necessary as it may be subject to pattern matching if it contains recognizable characters like *, ?, [], etc.. If extended globbing or pattern matching is enabled with shopt -s extglob, other forms like @(), !(), etc. will also be recognized as patterns. See Pattern Matching.
With operators like < and > it may still be necessary as I had once encountered a bug where not quoting the second argument caused different results.
As for the first operand, nothing applies.
Consider this simpler variation as well:
case "$1" in
1)
mv -- "${@:2}" ~/lab/Sun
;;
2)
mv -- "${@:2}" ~/lab/Moon
;;
3)
mv -- "${@:2}" ~/lab/Earth
;;
esac
Or condensed:
case "$1" in
1) mv -- "${@:2}" ~/lab/Sun ;;
2) mv -- "${@:2}" ~/lab/Moon ;;
3) mv -- "${@:2}" ~/lab/Earth ;;
esac
"${@:2}" is a form of substring expansion or array member expansion where 2 is the offset. This makes expansion start at the second value. With this we may not need to use shift.
The added -- prevents mv from recognizing filenames starting with dash (-) as invalid options.
Method 3
To answer the question of why this is happening, this behavior of [ aka test is documented in POSIX:
In the following list, $1, $2, $3, and $4 represent the arguments presented to test:
[…]
1 argument:Exit true (0) if $1 is not null; otherwise, exit false.
You’re passing it 1 argument, 2=1, which is not null, and therefore test exits with success.
As other posts (and shellcheck) point out, if you wanted to compare for equality, you would instead have to pass the 3 arguments 2, = and 1.
Method 4
I just want to recommend a portable yet also neater alternative. Bash is not universal (and if you don’t need universal, why are you writing a shell script?)
#! /bin/sh
action="$1"
shift
case "$action" in
1) dest=Sun ;;
2) dest=Moon ;;
3) dest=Earth ;;
*) echo "Unrecognized action code '$action' (must be 1, 2, or 3)" >&2; exit 1 ;;
esac
mv -- "<a href="https://getridbug.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="200460">[email protected]</a>" ~/lab/"$dest"
(Note to pedants: yes, I know the quotes around $action on the case "$action" in line are unnecessary, but I feel it is best to put them there anyway, so that future readers don’t have to remember that.)
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0