Comparison sign as variable - bash

Is it possible to set comparison sign as variable?
I want to do something like that:
var1=${1}
var2=${2}
condition=${3}
if [[ "${var1}" "${condition}" "${var2}" ]]; then
echo "Warning!"
fi
./alert.sh "10" "5" ">"

Setting it is no problem, it's using it that's difficult. (Your code raises a syntax error.)
You could switch from [[ ]] to test, though it's not exactly the same.
By the way, > is a string operator. You probably wanted -gt, the integer operator. See the link above for a table of operators.
var1="10"
var2="5"
condition="-gt"
if test "${var1}" "${condition}" "${var2}"; then
echo "Warning!"
fi
Output:
Warning!
Single square brackets also work (they're equivalent), but for some reason, ShellCheck detects a syntax error, so to make life easier with ShellCheck, I'd say just avoid it, even if that's a bug.
[ "${var1}" "${condition}" "${var2}" ]

An other way of doing such work is to construct & launch a second script.
It should be easier to debug (you can see & redo directly the cde)
echo "
#!/bin/bash
echo "es2 Start"
... write your cdes here ... with parameters you want
" > es2
chmod +x es2
./es2

Related

Conditional ZSH_THEME by terminal

I'm trying to make that when .zshrc when invoked chooses a specific theme based on which terminal amulator i'm running. For this I came up with:
current_terminal="$(ps -p$PPID -o cmd=)"
function choose_theme {
if [ $current_terminal=~'tilix' ];
then echo 'powerlevel9k/powerlevel9k';
else echo 'robbyrussell';
fi
}
ZSH_THEME="$(choose_theme)"
I don't get any error message when running and when I open on tilix it works just fine with the powerlevel9k theme, but just that, it doesn't seem to respect the condition and I don't know where might my mstake be =/
The output for the variable current_terminal in each terminal emulator i'm using are:
Tilix:
/usr/bin/tilix --gapplication-service
Default Terminal:
/usr/lib/gnome-terminal/gnome-terminal-server
So it's getting things wright, but setting up always the first option for some reason
This does not work due to two reasons:
You are using [ ... ] instead of [[ ... ]] for the check. The difference is that [[ ... ]] is part of the ZSH's syntax and [ (aka test) is a built-in command that tries to emulate the external test program. This matters because [ does not support the =~ operator, it is only available inside [[ ... ]].
The =~ (like any other operator) needs to be surrounded by white spaces. As a Unix shell ZSH tokenizes command on white spaces. In this case ZSH I would guess that ZSH only checks whether $current_terminal=~'tilix' evaluates to a non-empty string instead of comparing $current_terminal to 'tilix'. This is always the case, hence why you always get the powerlevel9k theme.
So the condition should look like this:
current_terminal="$(ps -p$PPID -o cmd=)"
function choose_theme {
if [[ $current_terminal =~ 'tilix' ]];
then echo 'powerlevel9k/powerlevel9k';
else echo 'robbyrussell';
fi
}
ZSH_THEME="$(choose_theme)"

difference between bash variable

I have 2 bash scripts. One is calling another.
Caller.sh
arg1="+hcpu_extra=111 bbb"
str="-y +hcpu_extra=111 bbb"
local cmd_re="(-y)(.*)"
if [[ $str =~ $cmd_re ]]
then
opt=${BASH_REMATCH[1]}
arg=${BASH_REMATCH[2]}
echo "matched $opt"
echo "matched $arg"
fi
./callee.sh -y $arg
## ./callee.sh -y $arg1
I found if I print $arg1 and $arg, they show the same value "+hcpu_extra=111 bbb" on the screen. But when I pass them respectively to the callee.sh as the argument. I got different results . So my question is , what is the difference between $arg and $arg1 from bash interpreter's point of view? .
First, the code won't work right as posted, because local can't be used except in a function.
If you remove the local or put this in a function, the only difference between arg and arg1 is that arg starts with a space (the one that was between "-y" and "+hcpu". but since you're expanding those variables without double-quotes around them, that'll be removed... unless you changed IFS to something that doesn't contain a space.
(BTW, variable references without double-quotes and changes to IFS are both things that can have weird effects, and are best avoided when possible.)
Anyway, my summary is: the posted code doesn't show the effect you've described; you appear to have left out something important. See How to create a Minimal, Complete, and Verifiable example.

Is [ $var ] an acceptable way to check for variables set/empty in bash?

I wrote some bash before reading this popular question. I noticed the way I was doing things doesn't show up in any of the answers so I was curious if there is a danger/bug to my logic that I am not seeing.
if [ ! $1 ] || [ $2 ]; then
echo "Usage: only one var." && exit 1
fi
As you can see, I am testing to see if there is one and only one parameter given on the command line. As far as I have tested, this works. Can someone pass along some more knowledge to a new bash user?
./script one '' oops
[ $2 ] will be false when $2 is the empty string.
And as that other guy points out in a comment, bash will split both strings, opening up a range of issues, including potential security holes.
This is clearer:
if [ $# != 1 ] ; then
echo "Usage: only one var."; exit 1
fi
Things that will break your test:
The first parameter is empty ("")
The second parameter is empty ("")
The first or second parameter has more words ("bla bla")
The parameters contain something that will be interpreted by test (e.g.: -z)
It is simply less clearer than using $#. Also the mere fact that I have to think about all the corner-cases which could potentially break the code makes it inferior.

$?<variable> in sh

Recently I come across below code ...
if [ ! $?target -o $target = "" ]; then
echo "Target is not set"
fi
I am curious to understand logic of above code snippet.
It seems that it is checking, if I am correct, whether "$taget" is set or not or "$target" is empty or not.
I google to find how $?variable works, but I didn't find any relative search results.
So please help me to understand how it works. Thanks in advance.
In some shells, csh for example, $?xyz will evaluate to 1 if xyz is set, otherwise it evaluates to 0.
All that snippet is doing is checking if either $target is not set at all or if it's set to an empty string. In both cases, it assumes it's not set.
Note that this is different from bash for example where $? is the return code from the last executed command. In that shell, you'll simply get the return code followed by the variable name, such as 0target.
I think your script is slightly mis-quoted,
if [ ! "$?target" -o "$target" = "" ]; then
echo "Target is not set"
fi
This will indeed print "Target is not set" when $target is unset, However A much more reliable method for doing this would be:-
if [ "x$foo" = "x" ]; then
echo "foo is not set"
fi
I put "#!sh" at the top, line 1 and ran it on a Mac OS 10.5.Terminal window, which says its bash...
The original script, with [ ! "$?target" -o "$target" = "" ]'
gets
try.sh: line 3: [: too many arguments
The version IanNorton suggests works:
Target is not set
I get the same results with #!bash on line 1, and no shell specification on line 1.
Your mileage may vary...

How to prevent code/option injection in a bash script

I have written a small bash script called "isinFile.sh" for checking if the first term given to the script can be found in the file "file.txt":
#!/bin/bash
FILE="file.txt"
if [ `grep -w "$1" $FILE` ]; then
echo "true"
else
echo "false"
fi
However, running the script like
> ./isinFile.sh -x
breaks the script, since -x is interpreted by grep as an option.
So I improved my script
#!/bin/bash
FILE="file.txt"
if [ `grep -w -- "$1" $FILE` ]; then
echo "true"
else
echo "false"
fi
using -- as an argument to grep. Now running
> ./isinFile.sh -x
false
works. But is using -- the correct and only way to prevent code/option injection in bash scripts? I have not seen it in the wild, only found it mentioned in ABASH: Finding Bugs in Bash Scripts.
grep -w -- ...
prevents that interpretation in what follows --
EDIT
(I did not read the last part sorry). Yes, it is the only way. The other way is to avoid it as first part of the search; e.g. ".{0}-x" works too but it is odd., so e.g.
grep -w ".{0}$1" ...
should work too.
There's actually another code injection (or whatever you want to call it) bug in this script: it simply hands the output of grep to the [ (aka test) command, and assumes that'll return true if it's not empty. But if the output is more than one "word" long, [ will treat it as an expression and try to evaluate it. For example, suppose the file contains the line 0 -eq 2 and you search for "0" -- [ will decide that 0 is not equal to 2, and the script will print false despite the fact that it found a match.
The best way to fix this is to use Ignacio Vazquez-Abrams' suggestion (as clarified by Dennis Williamson) -- this completely avoids the parsing problem, and is also faster (since -q makes grep stop searching at the first match). If that option weren't available, another method would be to protect the output with double-quotes: if [ "$(grep -w -- "$1" "$FILE")" ]; then (note that I also used $() instead of backquotes 'cause I find them much easier to read, and quotes around $FILE just in case it contains anything funny, like whitespace).
Though not applicable in this particular case, another technique can be used to prevent filenames that start with hyphens from being interpreted as options:
rm ./-x
or
rm /path/to/-x

Resources