What is -z in bash - linux

I am trying to understand the following code:
if [ -z "$1" ] || [ -z "$2" || [ "${3:-}" ]
then
echo "Usage: $0 <username> <password>" >&2
exit 1
fi
I want to understand what we mean by -z "$1" and "${3:-}" in the code.
Please also help me understand >&2 in the code.

1) Your code is not correct, you missed one ] bracket somewhere. Probably after [ -z "$2" block.
2) if statement executes following command(s) and then executes block of code enclosed in then .. fi or then .. else keywords if the return value of the command(s) is true (their exit code is 0)
3) [ is just an alias for the test command (try man test). This command takes several parameters and evaluates them. For example, used with -z "$something" flags would return true (0) if $something is not set or is an empty string. Try it:
if [ -z "$variable" ]; then
echo Variable is not set or is an empty string
fi
4) || statement is an OR. Next command would be executed if the previous one returned false statement. So in the statement
if [ -z "$variable" ] || [ -z "$variable2" ]; then
echo Variable 1 or variable 2 is not set or is an empty string
fi
command [ -z "$variable2" ] would be executed only if variable was empty. The same could be achieved with different syntax:
if [ -z "$variable" -o -z "$variable2" ]; then
echo Variable 1 or variable 2 is not set or is an empty string
fi
which should be faster, because it requires only one instance of the test program to be run. Flag -o means OR, so you could read it as:
If variable is not set/empty OR variable2 is not set/EMPTY...
5) Statement "[ ${3:-} ]" means return true if $3 (the third argument of the script) is set.
6) >&2 is a stream redirection. Every process has two outputs: standard output and error output. These are independent and could be redirected (for example) to be written to two different files. >&2 means "redirect standard output to the same location as standard error".
So to sum up: commands between then .. fi will be executed IF the script is run with $1 empty or $2 empty or $3 NOT empty That means that the script should be run with exactly two parameters. And if not, the echo message will be printed to standard error output.

-z STRING means the length of STRING is zero.
${parameter:-word} If parameter is unset or null, the expansion of word is substituted. In your case $3 is just set with a blank value, if $3 do not have any value.
&2 writes to standard-error. I mean the stdout value of the executed command is sent to stderr,

Related

unexpected return value 123

I'm trying to do a script that is used with two arguments - a file and an integer. It should check if the arguments are valid, otherwise exit with 1. Then it should either return 0 if the file is smaller than second argument, or echo size of the file to stdout. The script keeps returning value 123 instead of 1 or 0. Where is the problem? Thanks.
#!/bin/bash
if [ $# -eq 2 ];
then
if test $2 -eq $2 > /dev/null 2>&1
then
if [ -f $1 ];
then
if [ $(stat -c %s $1) -ge $2 ];
then
echo $(stat -c %s $1)
else
exit 0
fi
else
exit 1
fi
else
exit 1
fi
else
echo 042f9
exit 1
fi
I do not know where the "123" output comes from, but I would do it like this:
#!/bin/bash
# Must have 2 arguments
if [[ $# -ne 2 ]]
then
printf "042f9\n"
exit 1
fi
# File must exist
if [[ ! -f "$1" ]]
then
exit 1
fi
# File size > $2 check
filesize=$(stat -c %s "$1")
if [[ $filesize -ge $2 ]]
then
printf "%d" "$filesize"
else
exit 1
fi
A couple notes for your scripts (IMHO):
Like Mat mentioned in the comments, test 1 condition and exit right away. When I read your script, I had to go to the end to see what happens if the number of arguments is wrong. Logically there is nothing wrong with your code, it is just making it easier to read.
For bash, use [[ ]] to test if conditions.
I try never to call a function or command twice. That is why I stored the result of the stat command in a variable. If you use it more than once, store it, do not call the command again.
No need for ; since you put your then on the next line anyway.
Always double-quote your variables, especially if they are filenames. Weird filenames break so many scripts!
Finally use printf instead of echo. For simple cases, its the same, but echo does have some issues (https://unix.stackexchange.com/questions/65803/why-is-printf-better-than-echo).
Possible return values:
the size of the file, and the exit value is 0 ($?). The file is larger than argument 2 value.
"042f9", and the exit value is 1 ($?). Arguments error.
nothing, and the exit value is 1 ($?). Missing file error, or the file is smaller than argument 2 value.

How to execute a command in bash language and check its result

I'm trying to learn the bash language. How do I execute a Linux command with a dynamic argument and check whether or not the returning string is empty. For example:
if ls "my_directory123" == `emtpy string` then
....
end
If you are testing for an empty directory pass in the first positional parameter "$1", you can test:
if test -z "$(ls -A "$1")" ; then
or
if [ -z "$(ls -A "$1")" ]; then
which are equivalent uses of the test of [ keywords.
Assign the result of the command to a variable and compare it as a string.
result=$(ls "my_directory123")
if [ "$result" = "" ]
then
echo empty
fi
TEST=`ls`
if [$TEST == ""]; then
echo "do something"
fi
if you want to run this in the terminal you key in each line at a time. If you prefer you can put everything in a file prepend with
#!/bin/bash
to make an executable string once you run
chmod +x FILENAME
Need to call Command Substitution and check for returned value. Some think like this
x=$(ls path)
if [ -z "$x" ] ;then echo empty ; else echo no empty; fi

How to check if there is a parameter provided in bash?

I wanted to see if there is a parameter provided. But i don't know why this code wont work. What am i doing wrong?
if ![ -z "$1" ]
then
echo "$1"
fi
Let's ask shellcheck:
In file line 1:
if ![ -z "$1" ]
^-- SC1035: You need a space here.
In other words:
if ! [ -z "$1" ]
then
echo "$1"
fi
If, as per your comment, it still doesn't work and you happen to be doing this from a function, the function's parameters will mask the script's parameters, and we have to pass them explicitly:
In file line 8:
call_it
^-- SC2119: Use call_it "$#" if function's $1 should mean script's $1.
You could check the number of given parameters. $# represents the number of parameters - or the length of the array containing the parameters - passed to a script or a function. If it is zero then no parameters have been passed. Here is a good read about positional parameters in general.
$ cat script
#!/usr/bin/env bash
if (( $# == 0 )); then
echo "No parameters provided"
else
echo "Number of parameters is $#"
fi
Result:
$ ./script
No parameters provided
$ ./script first
Number of parameters is 1
$ ./script first second
Number of parameters is 2
If you would like to check the parameters passed to the script with a function then you would have to provide the script parameters to the function:
$ cat script
#!/usr/bin/env bash
_checkParameters()
{
if (( $1 == 0 )); then
echo "No parameters provided"
else
echo "Number of parameters is $1"
fi
}
_checkParameters $#
This will return the same results as in the first example.
Also related: What are the special dollar sign shell variables?

What means the -z value in an if expression on a Linux script?

In this script I found this if expression:
if [ -z $1 ]; then
echo "Usage: createpkg.sh <rev package>"
exit
else
CURRENT_VERSION=$1
fi
My problem is that I can't find what exactly means this -z value.
From the content of the echo I can deduct that (maybe) $1 variable represents the sotware version. and that (maybe) -z is a void value. So if I execute the script without passing to it the version of the software that I would packing it print me the correct procedure to execute the script.
But I am not sure about the real meaning of the -z value.
From man test:
-z STRING
the length of STRING is zero
So the condition:
if [ -z $1 ]; then
means "if the variable $1 is empty". Where $1 is probably the first parameter of the script: if you execute it like ./script <parameter1> <parameter2>, then $1=parameter1, $2=parameter2 and so forth.
help test tells:
String operators:
-z STRING True if string is empty.
In your example, the script would print Usage: createpkg.sh <rev package> and exit if an argument was not supplied.

Bourne Shell - How to identify that first parameter is ''

How can a Bourne Shell script know that the first parameter it received was '' (Two single quotation marks?
I've tried
if [ -z "$1" ] ; then
echo "Wrong number of parameters"
fi
But it seems that the $1 expands to an empty string and so is "$1".
When you type '' in command line shell translate it to argument - zero length string.
Check variable that holds the number or arguments (before checking -z "$1").
# check for any arguments
if [ "$#" -eq 0 ]; ...
# or -- has arguments and first one is ''
if [ "$#" -gt 0 -a -z "$1" ]; ...
See 'man test' for INTEGER comparison tests (-eq, -gt, etc).
EDIT (based on comments to question):
On windows (what shell do you use?) you have to check for '' (two characters) (cmd.exe passes it that way I think). On linux your script get an argument of string length zero.
if [ \( "$#" -gt 0 -a -z "$1" \) -o "$1" = "''" ]; ...
I assume what you mean is that a parameter was passed, but its value is empty. This is how to check it:
if [ $# -gt 0 -a "$1" = '' ]
then
echo '$1 was passed, but empty'
fi
If you want to check how many parameters were passed (empty or not), then use $# (argument count):
if [ $# -eq 0 ]
then
echo 'no parameters were passed'
fi
If you want to check the difference between two double quotation marks ("") and single quotation marks (''), there's no way to do that in Bourne shell alone. By the time your code is executed, these strings have been evaluated to the empty string.
'' is obviously not an empty string; it contains two characters. Do
[ "$1" = "''" ]
But then, on the (Linux) command line, you'll have to pass the parameter as
./script.sh "''"
if [ "$1" == "--" ] ; then
echo "Wrong number of parameters"
fi

Resources