What is if [ ! -f ] in shell script(grub.cfg)? - shell

I can understand if [ -f /etc/bashrc ] which just checks the existence of the file "/etc/bashrc". but what is "if [ ! -f ]". This line I came across at grub.cfg.
This may be a simple syntax but I couldn't get the answer by simply googling, as its not an usual syntax.
Thanks

The documentation for [ can be found at https://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html; the relevant section being:
If $1 is '!', exit true if $2 is null, false if $2 is not null.
Since the first argument is ! and the second argument is not the null string, the command returns false (non-zero).
Usually, this is an error, probably caused by a failure to properly quote a variable. At some point, the intent was probably to do something like if [ ! -f $filename ], and somewhere in the build chain the variable was the null string and that test expanded to if [ ! -f ].

Related

Argument isn't passed (bash)

I'm working with shell scripts.
I'm in the test section, where if an argument is passed:
The expression is true if, and only if, the argument is not null
And here I have implemented the following code:
[ -z $num ]; echo $?;
Your exit:
0
Why?
Firstly, [-z should be [ -z, otherwise you would be getting an error like [-z: command not found. I guess that was just a typo in your question.
It sounds like you're quoting the wrong part of the manual, which would apply to tests like this:
[ string ] # which is equivalent to
[ -n string ]
Either of which would return success (a 0) for a non-empty string.
With -z, you're checking that the length of the string is 0.
However, as always, be careful with unquoted variables, since:
[ -z $num ]
# expands to
[ -z ]
# which is interpreted in the same way as
[ string ]
i.e. your test becomes "is -z a non-empty string?", to which the answer is yes, so the test returns 0. If you use quotes around "$num" then the test does what you would expect.

Bash if [ -d $1] returning true for empty $1

So I have the following little script and keep wondering..
#!/bin/bash
if [ -d $1 ]; then
echo 'foo'
else
echo 'bar'
fi
.. why does this print foo when called without arguments? How is it that the test [-d ] returns true for an empty string?
From: info coreutils 'test invocation' (reference found through man test):
If EXPRESSION is omitted, test' returns false. **If EXPRESSION is a
single argument,test' returns false if the argument is null and true
otherwise**. The argument can be any string, including strings like
-d',-1', --',--help', and --version' that most other programs
would treat as options. To get help and version information, invoke
the commands[ --help' and `[ --version', without the usual closing
brackets.
Highlighting properly:
If EXPRESSION is a single argument, `test' returns false if the
argument is null and true otherwise
So whenever we do [ something ] it will return true if that something is not null:
$ [ -d ] && echo "yes"
yes
$ [ -d "" ] && echo "yes"
$
$ [ -f ] && echo "yes"
yes
$ [ t ] && echo "yes"
yes
Seeing the second one [ -d "" ] && echo "yes" returning false, you get the way to solve this issue: quote $1 so that -d always gets a parameter:
if [ -d "$1" ]; then
echo 'foo'
else
echo 'bar'
fi
The reason is plain and simple: The syntax does not match the case in which the -d is recognized as an operator working on a file name. It is just taken as a string, and each non-empty string is true. Only if a second parameter to -d is given, it is recognized as the operator to find out whether a given FILE is a directory.
The same applies to all the other operators like -e, -r, etc.
In your case, use double quotes to avoid running into that "problem":
[ -d "$1" ]
The reason that
[ -d ] && echo y
produces y is that the shell interprets it as a string in the test command and evaluates it to true. Even saying:
[ a ] && echo y
would produce y. Quoting from help test:
string True if string is not the null string.
That is why quoting variables is recommended. Saying:
[ -d "$1" ] && echo y
should not produce y when called without arguments.

Testing against -n option in BASH scripts always returns true

I am writing a bash script, in which I am trying to check if there are particular parameters provided. I've noticed a strange (at least for me) behavior of [ -n arg ] test. For the following script:
#!/bin/bash
if [ -n $1 ]; then
echo "The 1st argument is of NON ZERO length"
fi
if [ -z $1 ]; then
echo "The 1st argument is of ZERO length"
fi
I am getting results as follows:
with no parameters:
xylodev#ubuntu:~$ ./my-bash-script.sh
The 1st argument is of NON ZERO length
The 1st argument is of ZERO length
with parameters:
xylodev#ubuntu:~$ ./my-bash-script.sh foobar
The 1st argument is of NON ZERO length
I've already found out that enclosing $1 in double quotes gives me the results as expected, but I still wonder why both tests return true when quotes are not used and the script is called with no parameters? It seems that $1 is null then, so [ -n $1 ] should return false, shouldn't it?
Quote it.
if [ -n "$1" ]; then
Without the quotes, if $1 is empty, you execute [ -n ], which is true*, and if $1 is not empty, then it's obviously true.
* If you give [ a single argument (excluding ]), it is always true. (Incidentally, this is a pitfall that many new users fall into when they expect [ 0 ] to be false). In this case, the single string is -n.

shell: why [ -d ] returns true instead of false?

As is told here, the command [ -d FILE ] is used to check whether a file is directory.
However, when we miss the FILE parameter in the expression, it still returns true.
Why? How does shell interpret this expression then?
Example should be straightforward enough :)
$ [ -d /tmp ]
$ echo $? # prints 0
$ [ -d ]
$ echo $? # why prints 0 as well?
-d is only treated as an operator if [ receives 2 arguments. [ -d] is a one-argument form of the [ command, which exits with 0 if its single argument is non-null. Since -d is a non-null string, it exits 0.
[ -d "" ], on the other hand, is a two-argument form of the [ command, with the two arguments "-d" and "". Now the first argument is treated as a primary operator that acts on the second argument.
It gets interpreted as [ -n -d ]. In other words, since you've only provided one argument -d gets treated as if it were any other string, and as you can read in the man page:
-n STRING
the length of STRING is nonzero
STRING
equivalent to -n STRING

I'm getting EOF while looking for matching `"'

this is a bash script. im getting the error in the if statement line
# 2. read a line of input from the keyboard
read answer
if [-z "$answer"]
then
$answer=$default
else
$default=$answer
fi
i don't do much bash anymore, i can't see the error, ive tried
if [-z "$answer"]; then
and that failed as well with the same error. can anyone else see the error?
EDIT UPDATE
i changed it to this
read answer
if [ -z "$answer" ]
then
$answer=$defaultEntry
else
$defaultEntry=$answer
fi
and the same error occures
simply leave spaces between the brackets and condition:
if [ -z "$answer" ]
There should be a space between [ and -z, and between " and ].
[ is an alias to the test program.
[ is a program, which bash can execute.
[-z isn't, thus an error.
You need spaces around [ and ]. E.g.:
if [ -z "$answer" ]
then
$answer=$default
else
$default=$answer
fi
The reason for this is that [ is actually a shell builtin command.
[me#home]$ type [
[ is a shell builtin
[me#home]$ which [
/usr/bin/[
If you omit the space after [, you're mangling the command name into something that does not exist.
[me#home]$ [ -z "something" ] # OK. calling command [ with some args
[me#home]$ [-z "something" ] # fail. calling command [-z with some args
-bash: [-z: command not found
The [ command also checks that the last argument is ], therefore if you don't have spaces around that it becomes part of the previous argument and the [ command will complain:
[me#home]$ [ -z "something" ] # this runs fine becuase last arg is ]
[me#home]$ [ -z "something"] # will fail. last arg is "something"]
-bash: [: missing `]'
The space around the [ and ] is important, as others have pointed out.
Also, you should not be using $ when assigning to a variable.
Try this:
read answer
if [ -z "$answer" ]
then
answer=$defaultEntry
else
defaultEntry=$answer
fi
read answer
if [ -z "$answer" ] #Spaces!
then
answer=$default # Use "answer" and not "$answer"
else
default=$answer # Use "default" and not "$default"
fi
This now works except that I don't have a value for $default. I suspect you've done that elsewhere (as well as set a prompt).

Resources