I wanted to make a script which should take an argument and check if it is equal to a given word and then display a message accordingly. I use the bash shell of ubuntu OS. I tried something as per the tutorial - http://www.tech-recipes.com/rx/209/bournebash-shell-scripts-string-comparison/ and it failed.
#!/bin/bash
if ["$1"=="password"]
then
echo correct password
else
echo wrong password
fi
bash Script.sh password.
error message is -
[password=password]: command not found.
How to fix it ?
Whitespaces:
#!/bin/bash
if [ "$1" == "password" ]
then
echo correct password
else
echo wrong password
fi
The expression after the if is actually a command, and commands are delimited by whitespaces. So your command is ["$1"=="password"] that expands to [password==password], that obiously does not exist (/usr/bin/[password==password] anyone?).
In my corrected code, the command is [ (yes, there is a /bin/[) and the rest of the line are the arguments.
See man test for details (test is a kind-of-alias for [).
Related
I'm new to bash scripting, and I'm working on a script where the user enters a username and gets a list of the associated information from /etc/passwd. Unfortunately, I seem to be having trouble populating a variable from a command. The error message I'm getting suggests the if statement isn't being entered into, but I'm not sure why.
The script currently looks like this:
#!/bin/bash
#readifs
FILE=/etc/passwd
read -p "Enter a username > " user_name
file_info=$(grep "^$user_name:" $FILE)
if [ -n "$file_info" ]; then
IFS=":" read user pw uid gid name home shell <<< "$file_info"
echo "User = '$user'"
echo "UID = '$UID'"
echo "GID = '$GID'"
echo "Full Name = '$name'"
echo "Shell = '$shell'"
else
echo "No such user '$user_name'" > &2
exit 1
fi
When I run it, using a valid username, I get the following two lines:
readifs.sh: line 20: syntax error near unexpected token `&'
readifs.sh: line 20: ` echo "No such user '$user_name'" > &2'
I'm pretty sure I'm missing something obvious, or doing something bash doesn't allow but I'm too new to catch. Can anyone point out and correct the error in my script?
Thank you to Charles Duffy for all the great feedback on not just this script, but bash scripting and Stack Overflow in general.
I was able to fix the script as I wanted. I removed the ^ and : from the file_info line, which was stopping the grep command from finding the line I wanted. I also renamed $UID and $GID to use lower case letters, and removed the space in "> &2".
Thank you again for your assistance.
We can use bash -n script.sh to validate the syntax of a shell script. However, when I was trying to test this function, I noticed not all the syntax errors could be found by this option.
For example:
root#ubuntu:~/testenv# cat test
#!/bin/bash
SEND=1
if [ "$SEND" -eq 0 ]
echo no
fi
Now, let's test the script:
root#ubuntu:~/testenv# bash -n test
test: line 5: syntax error near unexpected token `fi'
test: line 5: `fi'
It works fine. However, if I just remove one of the bracket:
root#ubuntu:~/testenv# cat test
#!/bin/bash
SEND=1
if [ "$SEND" -eq 0
then
echo no
fi
root#ubuntu:~/testenv# bash -n test
root#ubuntu:~/testenv#
Nothing happened!
I also checked the man page of bash, it describes the "-n" is:
-n Read commands but do not execute them. This may be used to check a
shell script for syntax errors. This is ignored by interactive
shells.
It is a script file, so it shouldn't be an "interactive shell" right? So,how could this happen?
I'm guessing you have run into a very strange quirk of the way the shell implements single-bracketed conditionals: [ is a command, not a special character. Look in your system executable directory (probably /usr/bin) and you will find an executable file literally named [ which implements this command. When you write something like
[ "$SEND" -eq 0 ]
then you're actually invoking the command [ with four arguments:
The value of $SEND
The string -eq
The string 0
The string ]
The command [ checks that the last argument is ] (because it would look weird otherwise), then puts the remaining arguments together to form a condition and return the result of testing the condition.
Now, because [ is a command, it's not a syntax error to invoke that command with any set of arguments you like. Sure, if you leave off the trailing ], you will get an error, but that error comes from the command [, not from the shell. That means you have to actually run the script to get the error - the syntax checker won't see anything wrong with it. As far as bash is concerned, [ is just a command name, no different from, say, my_custom_conditional_test, and if you were to write
my_custom_conditional_test "$SEND" -eq 0
it would be obvious that this is fine, right? Bash thinks of [ the same way.
I should note that for efficiency, bash doesn't actually use the executable file /usr/bin/[; it has its own builtin implementation of [. But people expect [ to act the same way regardless of whether it's built in to the shell or not, so the Bash syntax checker can't give its own [ special treatment. Since it wouldn't be a syntax error to invoke /usr/bin/[ with no trailing ], it can't be a syntax error to invoke the builtin [ without a ].
You can contrast this with [[, which does more or less the same thing (testing a condition) but is given special meaning by the shell. [[ is a special token in shell syntax, not a command. If you write [[ instead of [, and you omit the corresponding trailing ]], you bet Bash is going to complain about a syntax error.
am having issue with grep as VESTACP is using it a lot.
i have file mysql.conf
HOST='localhost' USER='root' PASSWORD='xxxxxx' CHARSETS='UTF8,LATIN1,WIN1250,WIN1251,WIN1252,WIN1256,WIN1258,KOI8' MAX_DB='500' U_SYS_USERS='' U_DB_BASES='1' SUSPENDED='no' TIME='05:32:47' DATE='2016-03-20'
now when i run
echo host_str=$(grep "HOST='$1'" $VESTA/conf/mysql.conf)
i get empty result , although there is HOST in mysql.conf file which i pasted above in code
so any idea whats wrong with it
UPDATE :: Vesta db connect code block
host_str=$(grep "HOST='$1'" $VESTA/conf/mysql.conf)
eval $host_str
if [ -z $HOST ] || [ -z $USER ] || [ -z $PASSWORD ]; then
echo "Error: mysql config parsing failed"
log_event "$E_PARSING" "$EVENT"
exit $E_PARSING
fi
and i get
Error: mysql config parsing failed
$1 is the first parameter of your script.
So, host_str=$(grep "HOST='$1'" $VESTA/conf/mysql.conf) gets the line containing some variables from your file according to your parameter, and eval $host_str sets these variables in your script.
Therefore, your script needs an argument to know which host to look for in your file, in your case, it's localhost, so run: ./yourscript.sh localhost.
You probably don't want to use $1. Rather try this:
echo host_str=$(grep -o "HOST='[^']*'" $VESTA/conf/mysql.conf)
The [^']* expands to everything that happens to be in between the single quotes. The option -o makes sure you only get the matching string, not the whole line, if that is what you want.
I'm working on a bash script that will add users in a batch process. This code goes as follows:
#!/bin/bash
# A script that creates users.
echo "This is a script to create new users on this system."
echo "How many users do you want to add?"
read am
echo " "
for i in {0..$am..1}
do
echo "Enter a username below:"
read usern
sudo useradd $usern
sudo passwd $usern
echo " "
echo "User $am '$usern' added."
done
In this case, I wanted to make 4 users. I went through and entered the username "callum3" and set the password as "1234" for ease of login. Once I input everything (correctly, may I add) the terminal window displays the following.
User 4 'callum3' added.
This shows that my for loop isn't actually working, when I can see nothing wrong with it. I have tried using a while loop with no luck there either.
Am I making a rookie mistake here or is there something deeper going on?
Although I suspected it, for a better understanding on what could be wrong with your script I pasted it in shellcheck.net. That the problem is in the line:
for i in {0..$am..1}
Bash doesn't support variables in brace range expansions. That is, you cannot use a variable in an expression like {..}.
Instead, use seq. With seq $var you get a sequence from 1 (default) to $var:
for i in $(seq "$am")
I feel like I'm missing something in that nobody has suggested an arithmetic for loop:
for ((i=0; i<am; i++)); do
…
done
This has the particular benefit in bash of being both readable and not requiring a subshell.
You can use:
for i in `seq 0 $((am-1))`
do
...
done
Sequence will start from 0 and end at $am-1
The colon command is a null command.
The : construct is also useful in the conditional setting of variables. For example,
: ${var:=value}
Without the :, the shell would try to evaluate $var as a command. <=???
I don't quite understand the last sentence in above statement. Can anyone give me some details?
Thank you
Try
var=badcommand
$var
you will get
bash: badcommand: command not found
Try
var=
${var:=badcommand}
and you will get the same.
The shell (e.g. bash) always tries to run the first word on each command line as a command, even after doing variable expansion.
The only exception to this is
var=value
which the shell treats specially.
The trick in the example you provide is that ${var:=value} works anywhere on a command line, e.g.
# set newvar to somevalue if it isn't already set
echo ${newvar:=somevalue}
# show that newvar has been set by the above command
echo $newvar
But we don't really even want to echo the value, so we want something better than
echo ${newvar:=somevalue}.
The : command lets us do the assignment without any other action.
I suppose what the man page writers meant was
: ${var:=value}
Can be used as a short cut instead of say
if [ -z "$var" ]; then
var=value
fi
${var} on its own executes the command stored in $var. Adding substitution parameters does not change this, so you use : to neutralize this.
Try this:
$ help :
:: :
Null command.
No effect; the command does nothing.
Exit Status:
Always succeeds.