how to pass arguments like 750_000 from command line - literals

I am unable to pass values like 750_000 from command line to a function like usleep via shift. Still getting ".. isn't numeric".
Any ideas?
Thanks.

The 750_000 syntax is valid for numeric literals in source code, where it is simply ignored when populating the value. It is not valid when using a string that's already been created (such as read from commandline arguments) as a number. Numbers can be stored in strings with scientific notation as you noted. Alternatively you could remove the underscores yourself:
use strict;
use warnings;
use Time::HiRes 'usleep';
my $num = shift;
$num =~ tr/_//d;
usleep $num;

Sorry but answering my own question.
It can be done using exponent syntax.
examples:
1_000_000 can be written as 1e6
1_234_567 can be written as
1.234567e6

Related

Adding multiple user inputs into one variable in Bash

I am fairly new to unix bash scripting and need to know if this is possible. I want to ask user for their input multiple times and then store that input in to one variable.
userinputs= #nothing at the start
read string
<code to add $string to $userinputs>
read string
<code to add $string to $userinputs> #this should add this input along with the other input
so if the user enters "abc" when asked first time, it add's "abc" in $userinputs
then when asked again for the input and the user enters "123" the script should store it in the same $userinputs
this would make the $userinput=abc123
The usual way to concat two strings in Bash is:
new_string="$string1$string2"
{} are needed around the variable name only if we have a literal string that can obstruct the variable expansion:
new_string="${string1}literal$string2"
rather than
new_string="$string1literal$string2"
You can also use the += operator:
userinputs=
read string
userinputs+="$string"
read string
userinputs+="$string"
Double quoting $string is optional in this case.
See also:
How to concatenate string variables in Bash?
You can concatentate variables and store multiple strings in the same one like so:
foo=abc
echo $foo # prints 'abc'
bar=123
foo="${foo}${bar}"
echo $foo # prints 'abc123'
You can use the other variables, or the same variable, when assigning to a variable, e.g. a="${a}123${b}". See this question for more info.
You don't have to quote the strings you're assigning to, or do the ${var} syntax, but learning when to quote and not to quote is a surprisingly nuanced art, so it's often better to be safe than sorry, and the "${var}" syntax in double quotes is usually the safest approach (see any of these links for more than you ever wanted to know: 1 2 3).
Anyway, you should read into a temporary variable (read, by default, reads into $REPLY) and concatentate that onto your main variable, like so:
allinput=
read # captures user input into $REPLY
allinput="${REPLY}"
read
allinput="${allinput}${REPLY}"
Beware that the read command behaves very differently depending on supplied switches and the value of the IFS global variable, especially in the face of unusual input with special characters. A common "just do what I mean" choice is to empty out IFS via IFS= and use read -r to capture input. See the read builtin documentation for more info.

String formatting in Perl

I have a string whose middle part will be changed based on a condition.
Something like this:
"You have x number of problems";
The value of x has different text based on some if conditions.
One way I could do is to store "You have" in one variable and "number of problems" in another variable and
do something like sprintf("%s%d%s", $firstpart, $x, $secondpart);
Is there a better way to do this?
Generally, strings are constructed in Perl using interpolation: put the variable right in the string.
my $numProblems = 99;
my $text = "You got $numProblems problems, but Perl ain't one.";
This only works on simple variables, and things like array and hash access. Expressions and method calls don't work.
# Accessing a hash or array works.
my $text = "You got $numProblems{$user} problems, but Perl ain't one.";
# Method call does not work.
my $text = "You got $user->numProblems problems, but Perl ain't one.";
You can use the baby-cart "secret operator" to fool Perl into interpolating expressions.
my $text = "You got #{[$user->numProblems]} problems, but Perl ain't one.";
You can read about all the Gory Details Of Interpolation in perlop.
You can also use sprintf, but generally that's only when you need to do formatting. There's no need for separate variables for the start and end of the string.
my $text = sprintf "You got %d problems, but Perl ain't one.", $numProblems;

Unbound variable during url printing in bash/shell

I have 2 variables that I want to use to derive a 3rd variable:
export REGION_NAME=phx
export phx_url=https://www.google.com
I am trying to do the following:
echo "$((${REGION_NAME}_url))"
And I get the following error:
-sh: https://www.google.com: syntax error in expression (error token is "://www.google.com")
All I am trying to do is to derive an environment variable from an other one but it does not work simple like that. I think it has to be escaped and could not find anything online.
Thanks in advance for the help.
$((...)) is arithmetic expansion. You didn't mean that. Try normal variable expansion (with indirection) instead.
REGION_NAME=phx
phx_url=https://www.google.com
R_VAR=${REGION_NAME}_url
echo "${!R_VAR}"
One possible solution is using eval like:
var="phx"
eval "${var}_url='some'"
echo $phx_url #prints "some"
But, I not recommending this (because the eval could be pretty dangerous).
Instead of use associative arrays (aka hash variable), like:
declare -A urls
var="phx"
urls[$var]="some2"
echo "${urls[phx]}" #prints "some2"

error in Integer comparison in bash

I am trying to perform a simple integer comparison in bash, which I am new to using, and my methods are causing an error. Any advice would be appreciated.
My basic logic is that I am reading in hurricane track points. There may be multiple entries for the same track_id, with different pressure values. What I want to do is store only one entry per track_id into the array track_id_poly; the case with the lowest pressure. So I am looping through each line, and attempting to compare the current pressure (for $int), with the previous track pressure ($int - 1), and if it is lower, replace the previous array value with the new lower pressure. I hope that makes sense. My code is below.
int=0
while read track_id ppres_inter
do
printf -v pres_inter "%.0f" "$pres_inter"
echo pressure $pres_inter
case $int in
0)
Track_id_poly[$int]=$track_id
Pres_inter_poly[$int]=$pres_inter
((int=int+1)) ;;
*)
if [[ $track_id == ${Track_id_poly[$int-1]} ]]
then
if (( $pres_inter -lt ${Pres_inter_poly[$int-1]} ))
then
Track_id_poly[$int-1]=$track_id
Pres_inter_poly[$int-1]=$pres_inter
fi
else
Track_id_poly[$int]=$track_id
Pres_inter_poly[$int]=$pres_inter
((int=int+1))
fi ;;
esac
done <$file_poly
int_poly=$int
echo Number of polygon crossings from set $i is $int_poly
The line that is causing me problems is the integer comparison for $pres_inter.
if (( $pres_inter -lt ${Pres_inter_poly[$int-1]} ))
I get the following error:
line 41: 96800 -lt 98759 : syntax error in expression (error token is "98759 ")
Any tips to fix this problem would be appreciated. Probably a simple fix!
The ((...)) operator does not accept the same syntax as the test, [..], or [[...]] commands. To compare two numbers in ((...)), you would use actual > or < symbols:
$ (( 4 > 2 )) && echo '4 is bigger!'
4 is bigger!
See the ARITHMETIC EVALUATION section of the bash(1) man page for more information (or here).
My shell scripting is rusty for good reason but you may to review that line and either use "[[ ]]" instead of "(( ))", or use "<" instead of "-lt" . See bash: double or single bracket, parentheses, curly braces
However, the main tip I'd give to you is to stop using bash for things that involve anything beyond simple program invocation and switch to a scripting language (Perl, Python, ...) because it won't only be more robust, it'll be easier to get the job done and it'll also run faster.
In bash "((expression))" is differently evaluated. So you cannot use the operator "-lt", instead you can use the normal operator <.
For further info see the man page of bash:
((expression))
The expression is evaluated according to the rules
described below under ARITHMETIC EVALUATION. If the value of the
expression is non-zero, the return status is 0; otherwise the return
status is 1. This is exactly equivalent to let "expression".
And the paragraph ARITHMETIC EVALUATION explains further possibilities.

Default values for the arguments to a Unix shell script?

Normally when a parameter is passed to a shell script, the value goes into ${1} for the first parameter, ${2} for the second, etc.
How can I set the default values for these parameters, so that if no parameter is passed to the script, we can use a default value for ${1}?
You can't, but you can assign to a local variable like this: ${parameter:-word} or use the same construct in the place you need $1. this menas use word if _paramater is null or unset
Note, this works in bash, check your shell for the syntax of default values
You could consider:
set -- "${1:-'default for 1'}" "${2:-'default 2'}" "${3:-'default 3'}"
The rest of the script can use $1, $2, $3 without further checking.
Note: this does not work well if you can have an indeterminate list of files at the end of your arguments; it works well when you can have only zero to three arguments.
#!/bin/sh
MY_PARAM=${1:-default}
echo $MY_PARAM
Perhaps I don't understand your question well, yet I would feel inclined to solve the problem in a less sophisticated manner:
! [[ ${1} ]] && declare $1="DEFAULT"
Hope that helps.

Resources