Using "false" in if statement KSH - if-statement

My code:
if $bVar1 && $bVar2
then
echo "bVar1 & bVar2 are true"
elif $bVar3 && !$bVar4
then
echo "bVar3 is true; bVar4 is false"
fi
The !$bVar4 part does not work as expected. I've tried:
elif $bVar3 && !$bVar4
elif $bVar3 && !${bVar4}
elif $bVar3 && !$(bVar4)
but I cannot get this line to return true when bVar3=true and bVar4=false.
For completeness, variables are assigned like this:
bVar3=true
bVar4=false
(Of course, I can add a nested if statement within the elif like this:
if $bVar1 && $bVar2
then
echo "bVar1 & bVar2 are true"
elif $bVar3
then
if $bVar4
then
: #pass
else
echo "bVar3 is true; bVar4 is false"
fi
fi
but that is unnecessary, isn't it? BTW - I did try this and this code works.)

Shells are finicky with respect to whitespace. For example, in an interactive bash shell with certain settings, !$bVar4 will attempt to do history expansion as a result of the !, but ! $bvar4 will expand the string $bvar4, attempt to execute the resulting string, and then negate the return value. Adding a space after the ! is probably necessary to ensure the expected semantics.

Related

In conky, how do I nest a variable within a template?

In conky, how do I nest a variable within a template?
EXAMPLES:
${template2 enp0s25} <- WORKS (fixed string)
${template2 ${gw_iface}} < FAILS (nested variable)
${template2 ${execpi 10 ls -d /sys/class/net/enp* 2> /dev/null | sed -e 's,/sys/class/net/,,'}} <- FAILS (nested variable command)
I've also tried (and failed):
${combine ${template2 ${gw_iface}}}
${combine ${template2} ${gw_iface}}
Here is "template2":
template2 = [[
${if_existing /proc/net/route \1}Wired Ethernet ("\1"):
- MAC: ${execi 5 cat /sys/class/net/\1/address} IP: ${addr \1}
- Max: ${execi 5 /sbin/ethtool '\1' 2>/dev/null | sed -n -e 's/^.*Speed: //p'}${goto 190}${if_match ${downspeedf \1} > 0}${font :bold:size=14}${endif}Down: ${downspeedf \1}kB/s${font}${goto 370}${if_match ${upspeedf \1} > 0}${font :bold:size=14}${endif}Up: ${upspeedf \1}kB/s${font}
${endif}]]
Thanks for the help.
Templates are a little limited as you cannot evaluate the parameters before they are passed through. One workaround is to use a bit of lua code to do the eval explicitly and then parse the template. For example,
conky.config = {
lua_load = '/tmp/myfunction.lua',
...
};
conky.text = [[
${lua myeval template2 ${gw_iface}}
]]
Create the lua file, /tmp/myfunction.lua holding
function conky_myeval(tpl, var1)
v = conky_parse(var1)
cmd = "${"..tpl.." "..v.."}"
return conky_parse(cmd)
end
The lua function takes the name of the template, tpl, and the parameter to evaluate, var1. It evaluates the latter using conky_parse() to, say, string "xxx", then constructs a new string "${template2 xxx}", which is parsed and returned as the value of the ${lua} call.
The same can be done for the longer example ${execpi ...} too.

Recursively replacement on a variable

Given this associative array:
declare -A variables=(
[prefix]='/usr'
[exec_prefix]='#prefix#'
[libdir]='#exec_prefix#/lib'
)
I would like to replace any occurrence of the pattern #([^#/]+)# (e.g. #prefix#, with prefix being the capture) with the value that's associated to the capture (e.g. /usr for prefix) in all its values, such that the substitution be performed recursively until there are no more occurrences. The steps for each key in the array would be:
Retrieve the value associated to it and perform (2) on it.
Check if there is a match of the pattern in the given string.
If there isn't any, return the given string.
If there's a match:
Perform (1) on the capture and keep the result.
Replace the match by the result.
Perform (2) on the resulting string.
Drop the previous value associated to the key and associate to it the last string returned.
Whatever the approach, the desired result is:
prefix=/usr
exec_prefix=/usr
libdir=/usr/lib
Additional requirements:
Self references (e.g. prefix=#prefix#) will not occur.
If possible, use only Bash builtins.
Example in Lua:
local variables={
prefix="/usr",
exec_prefix="#prefix#",
includedir="#prefix#/include",
libdir="#exec_prefix#/lib",
random_one_to_show_off_fancy_recursion="#prefix##libdir##includedir#"
}
function replacer( variable )
return compute_value(variables[variable])
end
function compute_value( s )
return s:gsub('#([^#/]+)#',replacer)
end
local variable, value = next(variables)
while variable do
variables[variable] = compute_value(value)
print( string.format('%-39s\t%s', variable, variables[variable]) )
variable, value = next(variables,variable)
end
The (pure Bash) code below assumes that '##' is left unchanged and '#xyz#' is left unchanged when 'xyz' is not a variable. It also attempts to detect recursive variable definitions, including indirect ones (e.g. [a]=#b# [b]=#c# [c]=#a#).
# Regular expression for a string with an embedded expansion
# For a string of the form 'u#v#w', where 'u' and 'v' do not contain '#':
# u -> BASH_REMATCH[1]
# v -> BASH_REMATCH[2]
# w -> BASH_REMATCH[3]
readonly EXPANSION_RX='^([^#]*)#([^#]*)#(.*)$'
# First pass tries to expand all variables
vars_to_expand=( "${!variables[#]}" )
while (( ${#vars_to_expand[*]} > 0 )) ; do
old_vars_to_expand=( "${vars_to_expand[#]}" )
vars_to_expand=()
for var in "${old_vars_to_expand[#]}" ; do
val=${variables[$var]}
unexpanded=$val
newval=
while [[ $unexpanded =~ $EXPANSION_RX ]] ; do
newval+=${BASH_REMATCH[1]}
v=${BASH_REMATCH[2]}
unexpanded=${BASH_REMATCH[3]}
if [[ $v == "$var" ]] ; then
echo "ERROR - Expanding '#$var#' in '$var'" >&2
exit 1
elif [[ -z $v ]] ; then
# The empty string can not be a hash key (Duh!)
newval+=#$v#
else
newval+=${variables[$v]-#$v#}
fi
done
newval+=$unexpanded
if [[ $newval != "$val" ]] ; then
# An expansion has occurred.
# Update the variable value
variables[$var]=$newval
# Further expansions may be possible, so add the variable to the
# list of variables to be expanded again
vars_to_expand+=( "$var" )
fi
done
done

CoffeeScript String Comparison

In CoffeeScript, is there a way to simplify the following:
if(value === "something" || value === "else" || value === "wow"){}
I've tried:
if value is "something" or "else" or "wow"
But this produces the literal output of this:
if(value === "something" || "else" || "wow){}
Is there a way to check if a string is one of multiple values (OR or AND) in CoffeeScript?
I think you probably want
if value in ['something', 'else', 'wow']

perl regular expression matching more than it should -- due to shell escaping

I have a lot of files that need one line changed.
Here is the code:
GetOptions ('full' => \$full,
'dbno=s' => \$dbno,
'since=s' => \$since,
'printSQL' => \$printSQL,
'nwisDB=s' => \$nwisDBOption);
# Find the NWISDB to be extracted
if ($nwisDBOption eq '') {
$nwisdb = &WSCExtractor::getNwisdb;
} else {
$nwisdb = uc($nwisDBOption);
}
Here is what I want:
GetOptions ('full' => \$full,
'dbno=s' => \$dbno,
'since=s' => \$since,
'printSQL' => \$printSQL,
'nwisDB=s' => \$nwisDBOption) || &WSCExtractor::usage();
# Find the NWISDB to be extracted
if ($nwisDBOption eq '') {
$nwisdb = &WSCExtractor::getNwisdb;
} else {
$nwisdb = uc($nwisDBOption);
}
Here is the perl command I am using:
perl -pi -e "s/\\\$nwisDBOption\);/\\\$nwisDBOption\) || \&WSCExtractor::usage\(\);/" extractor-template
Here is the result:
GetOptions ('full' => \$full,
'dbno=s' => \$dbno,
'since=s' => \$since,
'printSQL' => \$printSQL,
'nwisDB=s' => \$nwisDBOption) || &WSCExtractor::usage();
# Find the NWISDB to be extracted
if ($nwisDBOption eq '') {
$nwisdb = &WSCExtractor::getNwisdb;
} else {
$nwisdb = uc($nwisDBOption) || &WSCExtractor::usage();
}
It is matching the second instance of $nwisDBOption even though it does not have a \ in front of it. I have tried adding more \ in front in case perl was eating them. It did not match then. Thanks.
I'm assuming you're on a Unixish OS, not Windows. Since you're using double quotes around your code, the shell is parsing it and — among other things — replacing double backslashes with single one. So the code perl sees is actually not:
s/\\\$nwisDBOption\);/\\\$nwisDBOption\) || \&WSCExtractor::usage\(\);/
but:
s/\$nwisDBOption\);/\$nwisDBOption\) || \&WSCExtractor::usage\(\);/
You can easily confirm this by running the command:
echo "s/\\\$nwisDBOption\);/\\\$nwisDBOption\) || \&WSCExtractor::usage\(\);/"
Anyway, there are a few ways to fix the problem. The ones I'd recommend would be either to use single quotes instead double quotes, or simply to write your code into an actual Perl script file and run it that way.
However, if you really wanted to, you could just double all backslashes in your code.

Is there a good way to replace home directory with tilde in bash?

Im trying to work with a path and replace the home directory with a tilde in bash, Im hoping to get it done with as little external programs as necessary. Is there a way to do it with just bash. I got
${PWD/#$HOME/\~}
But thats not quite right. It needs to convert:
/home/alice to ~
/home/alice/ to ~/
/home/alice/herp to ~/herp
/home/alicederp to /home/alicederp
As a note of interest, heres how the bash source does it when converting the \w value in the prompt:
/* Return a pretty pathname. If the first part of the pathname is
the same as $HOME, then replace that with `~'. */
char *
polite_directory_format (name)
char *name;
{
char *home;
int l;
home = get_string_value ("HOME");
l = home ? strlen (home) : 0;
if (l > 1 && strncmp (home, name, l) == 0 && (!name[l] || name[l] == '/'))
{
strncpy (tdir + 1, name + l, sizeof(tdir) - 2);
tdir[0] = '~';
tdir[sizeof(tdir) - 1] = '\0';
return (tdir);
}
else
return (name);
}
I don't know of a way to do it directly as part of a variable substitution, but you can do it as a command:
[[ "$name" =~ ^"$HOME"(/|$) ]] && name="~${name#$HOME}"
Note that this doesn't do exactly what you asked for: it replaces "/home/alice/" with "~/" rather than "~". This is intentional, since there are places where the trailing slash is significant (e.g. cp -R ~ /backups does something different from cp -R ~/ /backups).
See this unix.stackexchange answer:
If you're using bash, then the dirs builtin has the desired
behavior:
dirs +0
~/some/random/folder
That probably uses Bash's own C code that you pasted there. :)
And here's how you could use it:
dir=... # <- Use your own here.
# Switch to the given directory; Run "dirs" and save to variable.
# "cd" in a subshell does not affect the parent shell.
dir_with_tilde=$(cd "$dir" && dirs +0)
Note that this will only work with directory names that already exist.