Non-integer counter for do ... until loop in bash - bash

I'm currently using bash 3.2.51
I'm trying to create a simple do until loop that steps up in small intervals of 0.05. My current code is shown below, it works fine for whole numbers but when I use non-integer it fails with errors.
x=0.05
until [ $x -gt 1.20 ]
do
//some code //
x =$((x+0.05))
done
Any help would be much appreciated.

bash currently doesnt support float variables, you need to delegate the task to other programs.
$echo $((1+0.05))
bash: 1+0.05: syntax error: invalid arithmetic operator (error token is ".05")
$ echo $(echo "1+0.05" | bc -l)
1.05
$ bash -version
GNU bash, version 4.3.30(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$
more info: https://unix.stackexchange.com/questions/40786/how-to-do-integer-float-calculations-in-bash-or-other-languages-frameworks

Related

Where is this bash line length limit coming from?

On Solaris 11 running Bash 4.4.19 (the standard install?) there appears to be a 256 character limit of sorts on the input line. I'd like to understand where this limit is coming from.
I've skimmed the man page, but I don't find anything which addresses this. This happens only when the readline library is not in use. In the lines below, the length of echo 678[...]23456 is 256 characters
sfmg10 0 5:37pm> uname -a
SunOS sfmg10 5.11 11.4.6.4.0 sun4v sparc sun4v
sfmg10 0 5:37pm> /usr/bin/bash --version
GNU bash, version 4.4.19(1)-release (sparc-sun-solaris2.11)
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
sfmg10 0 5:38pm> /usr/bin/bash -norc -noprofile
bash-4.4$ set -o emacs
bash-4.4$ echo 6789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678
6789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678
bash-4.4$ set +o emacs
bash-4.4$ echo 67890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456
67890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456
bash-4.4$ echo 678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567
bash-4.4$ echo 6789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678
bash: 8: command not found
The first line with an echo is 258 characters and executes as expected.
The second echo line is 256 characters executes as expected.
The third echo line is 257 characters and produces no output.
The fourth echo line is 258 characters and bash appears to throw out the first 257 characters and then execute the remaining characters.
I've tried this on several Linux, Mac OSX, and FreeBSD systems and could not reproduce the odd behavior.
On Solaris 9 with bash 2.05.0(1)-release and Solaris 10 with bash 3.2.57(1)-release (the same version as one of the Mac OSX boxes I get the same odd behavior as Solaris 11. I had thought that Solaris 10 was slightly different, but that was because I was accessing it through putty instead of an xterm. The putty/xterm difference is described in my comment below.
Why does bash throw out the first 257 characters of lines 257 characters or longer? Is this a bug or a feature? Is this caused by bash, Solaris, or something else? Can I change this number without re-compiling bash?

How to separate outputs of one-line multiple commands?

I have installed some GNU packages on my macOS Sierra, which include bash, coreutils, which, etc. Now I can use which -a bash | xargs -I % echo % "--version" | sh to check all version info of bash, but there is no separation between two version info:
$ which -a bash | xargs -I % echo % "--version" | sh
GNU bash, version 4.4.12(1)-release (x86_64-apple-darwin16.3.0)
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
# There should be one or more blank lines as separation.
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin16)
Copyright (C) 2007 Free Software Foundation, Inc.
I tried ... echo -e % "--version\n" ..., but it can't work. Please help me, thanks.
For a bit more control of the output, use a loop:
which -a bash |
while read cmd; do
printf '%s\t----------\n' "$cmd"
command "$cmd" --version
echo
done
I'd write this as follows:
IFS=: read -r -a path_entries <<<"$PATH"
find "${path_entries[#]}" -maxdepth 1 -name bash -type f -exec '{}' --version ';'
Note:
No use of which. This isn't a shell builtin in bash, so it gives you none of the benefits you'd get from type (ie. awareness of functions and aliases); and because its output is line-oriented, it can't unambiguously emit all possible filenames (such as those containing newlines -- which, yes, are valid).
No reliance on line-oriented content, generally. When the placeholder ({}) is passed as a single token, find -exec substitutes the exact filename returned for that token. Because the domain of possible argv values (all valid C strings, which is to say, no strings containing NULs) matches the domain of possible filenames on common systems, this avoids introducing potential bugs.
No generating text and piping that to an interpreter. This is an extremely error-prone technique, inducing shell-injection vulnerabilities: Consider what would happen if a PATH contained /tmp/$(rm -rf ~), and that directory contained a bash executable.

Bash unbound variable array (script: s3-bash)

I am working with: s3-bash, when I run it in my local environment (OS X 10.10.1) I don't have any problems, when I try to run it on a ubuntu server 14.04.1 I get the following error:
./s3-common-functions: line 66: temporaryFiles: unbound variable
./s3-common-functions: line 85: temporaryFiles: unbound variable
I've looked at the s3-common-functions script and the variable looks to be initialized properly (as an array):
# Globals
declare -a temporaryFiles
But there is a note in the comment, and I'm sure if it's related:
# Do not use this from directly. Due to a bug in bash, array assignments do not work when the function is used with command substitution
function createTemporaryFile
{
local temporaryFile="$(mktemp "$temporaryDirectory/$$.$1.XXXXXXXX")" || printErrorHelpAndExit "Environment Error: Could not create a temporary file. Please check you /tmp folder permissions allow files and folders to be created and disc space." $invalidEnvironmentExitCode
local length="${#temporaryFiles[#]}"
temporaryFiles[$length]="$temporaryFile"
}
There appears to be a bash behaviour change at play here.
Found by kojiro: CHANGES
hhhh. Fixed a bug that caused `declare' and `test' to find variables that
had been given attributes but not assigned values. Such variables are
not set.
$ bash --version
GNU bash, version 3.2.25(1)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2005 Free Software Foundation, Inc.
$ set -u
$ declare -a tF
$ echo "${#tF[#]}"
0
vs.
$ bash --version
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ set -u
$ declare -a tF
$ echo "${#tF[#]}"
0
vs.
$ bash --version
GNU bash, version 4.3.30(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ set -u
$ declare -a tF
$ echo "${#tF[#]}"
-bash: tF: unbound variable
You can use declare -a tF=() on the newer bash versions to work around this.
$ declare -a tF=()
$ echo "${#tF[#]}"
0
Bash can substitute an empty value into unset variables using a dash.
set -u
my_array=()
printf "${my_array[#]-}\n"
This specific example will print nothing, but it will not give you an unbound variable error either.
Stolen from Bash: Error `Unbound variable' when appending to empty array1.
However, when used for a loop, you get one iteration (not zero) then:
for i in "${my_array[#]-}"
do
echo $i
done
Expectation might be to get zero iterations.
It could be fixed this way then:
[ ${#my_array[#]} -gt 0 ] &&
for i in "${my_array[#]}"
do
echo $i
done
Changed declaration of array for temporaryfiles
declare -a temporaryFiles
to:
temporaryFiles=()
Why this is different / non-function in ubuntu 14.04.1 Linux 3.13.0-32-generic x86_64 versus OS X I am not sure ?
find $fullfolder -type f |
while read fullfile
do
filename=$(basename "$fullfile")
ext=$([[ $filename = *.* ]] && printf %s ${filename##*.} || printf 'NONE')
arr+=($ext)
echo ${#arr[#]}
done
echo ${#arr[#]}
Why does the ${#arr[#]} inside the for loop produce the correct result but the one outside gives 0?

How to properly escape string to test in shell?

I have the following function:
testit()
{
[ "$1" == "OK" ] && echo "good" || echo "bad"
}
but it doesn't work as expected. I can call it with:
testit 'OK' #good
testit 'abc' #bad
but when I call it with:
testit '('
it fails with: "sh: closing paren expected". I've quoted the string to test, so why it acts like there are no quotes?
This is most likely a bug in your shell implementation. I have tested your code on the latest CentOS and it works fine.
testit '('
bad
sh -version
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Here's an ugly workaround:
if [ "x$1" = "xOK" ]; ...

Bash Array Feature or Bug?

While attempting to debug a job submission script, I ended up narrowing down the bug to this:
[testuser#bes ~]$ var=( 1 foo1*bar4 echo 1*4=4 )
[testuser#bes ~]$ echo "${var[#]}"
1 foo1*bar4 echo 1*4=4
[testuser#bes ~]$ cd /data/testuser/jobs/example/a16162/
[testuser#bes a16162]$ var=( 1 foo1*bar4 echo 1*4=4 )
[testuser#bes a16162]$ echo "${var[#]}"
1 foo1-bar4 foo1*bar4 echo 1*4=4
[testuser#bes a16162]$
That is an uncut transcript of a fresh bash session. Anyone have any idea how that one works? Is this some archaic feature of bash that I've never heard of before, or just a really weird bug?
Versions (yes I know it's out dated):
GNU bash, version 3.2.25(1)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2005 Free Software Foundation, Inc.
Linux bes 2.6.18-194.11.3.el5 #1 SMP Mon Aug 30 16:19:16 EDT 2010 x86_64 x86_64 x86_64 GNU/Linux
EDIT: This is for something that needs to process a user-passed array, and I'd rather use this method than a triplet of rather awkward awk hacks. They're trivial "extract element 2" sorts of things, which is why using the array seems nicer.
Globs are still globbed when the array is formed. If you don't want this then you need to quote or escape them.
$ var=( 1 "foo1*bar4" echo "1*4=4" )
What does ls /data/testuser/jobs/example/a16162/foo1* reveal?
You can disable filename globbing with set -f and re-enable it with set +f

Resources