How to handle integers in bash with values larger than 2^63
I'd recommend using bc
with its arbitrary precision.
Bash overflows at 263:
$ A=$(( 2**63 - 1 ))
$ echo $A
9223372036854775807
$ echo $(( A+1 ))
-9223372036854775808
bc can handle this:
$ bc <<< "$A+1"
9223372036854775808
These numbers have to be handled with bc for everything from now on, though. Using [[ ]]
, they don't seem to overflow, but comparison doesn't work properly:
$ B=$(bc <<< "$A+1")
$ echo $B
9223372036854775808
$ set -vx
$ [[ $B -gt -$A ]] && echo true
[[ $B -gt -$A ]] && echo true
+ [[ 9223372036854775808 -gt -9223372036854775807 ]]
And in arithmetic context (( ))
, they overflow:
$ echo $(( B ))
-9223372036854775808
so the comparison doesn't work either:
$ (( B > A )) && echo true || echo false
false
Handling them with bc:
$ bc <<< "$B > $A"
1
and since within (( ))
non-zero results evaluate to true and zero to false, we can use
$ (( $(bc <<< "$B > $A") )) && echo true
true
Bash script size limitation?
Yes, this is a limitation with bash
.
It's not a script size limit; rather it's a limit to the depth of the parser stack, which has the effect of restricting the complexity of certain constructs. In particular, it will restrict the number of elif
clauses in an if
statement to about 2500.
There is a longer analysis of this problem with respect to a different syntactic construct (iterated pipes) in my answer to a question on the Unix & Linux stackexchange site.
case
statements don't have this limitation, and the sample you provide certainly looks like a good match for a case
statement.
(The difference with case
statements is that the grammar for if
conditional statements, like that of pipe constructs, is right recursive, while the grammar for case
statements is left recursive. The reason the limitation on if
statements is different from the limitation on pipes is that the grammatical construct for an elif
clause has one more symbol, so each repetition uses four stack slots rather than three.)
If the case
statement doesn't work for you -- or even if it does -- you could try building a precompiled binary search tree of if
statements:
if (( task_number < 8 )); then
if (( task_number < 4 )); then
if (( task_number < 2 )); then
if (( task_number < 1)); then
# do task 0
else
# do task 1
fi;
elif (( task_number < 3 )); then
# do task 2
else
# do task 3
fi
elif (( task_number < 6 )); then
if (( task_number < 5 )); then
# do task 4
else
# do task 5
fi
elif (( task_number < 7 )); then
# do task 6
else
# do task 7
fi
elif (( task_number < 12 )); then
if (( task_number < 10 )); then
if (( task_number < 9 )); then
# do task 8
else
# do task 9
fi
elif (( task_number < 11 )); then
# do task 10
else
# do task 11
fi
elif (( task_number < 14 )); then
if (( task_number < 13 )); then
# do task 12
else
# do task 13
fi
elif (( task_number < 15 )); then
# do task 14
else
# do task 15
fi
Because each complete if
statement only occupies a single stack node after it is recognized, the complexity limitation will be on the nesting depth of the if
statements rather than the number of clauses. As an additional bonus, it will execute a lot fewer comparisons in the average case.
If you have no alternative other than a sequential list of conditions, you can use separate if
statements:
while :; do
if condition1; then
# do something
break; fi; if condition2; then
# do something
break; fi; if condition3; then
# do something
break; fi; if condition4; then
# do something
break; fi
# No alternative succeeded
break
done
The unconventional indent is intended to illustrate the simple program transformation: simply replace every elif
with break;fi;if
and surround the whole thing with a while
(to provide the target for the break
s.)
Bash command line and input limit
The limit for the length of a command line is not imposed by the shell, but by the operating system. This limit is usually in the range of hundred kilobytes. POSIX denotes this limit ARG_MAX
and on POSIX conformant systems you can query it with
$ getconf ARG_MAX # Get argument limit in bytes
E.g. on Cygwin this is 32000, and on the different BSDs and Linux systems I use it is anywhere from 131072 to 2621440.
If you need to process a list of files exceeding this limit, you might want to look at the xargs
utility, which calls a program repeatedly with a subset of arguments not exceeding ARG_MAX
.
To answer your specific question, yes, it is possible to attempt to run a command with too long an argument list. The shell will error with a message along "argument list too long".
Note that the input to a program (as read on stdin or any other file descriptor) is not limited (only by available program resources). So if your shell script reads a string into a variable, you are not restricted by ARG_MAX
. The restriction also does not apply to shell-builtins.
bash variable for upper limit of for loop number syntax
Don't use {...}
; use a C-style for loop.
for ((i=1; i <= $n; i++)); do
Brace expansion occurs before parameter expansion, so you can't generate a variable-length sequence without using eval
. This is also more efficient, as you don't need to generate a possibly large list of indices before the loop begins.
Limit the Number of Characters with Regex
First, your users are going to hate you if "incorrect format" is all the info you give them. Second, you're asking a lot of one regex. Yes, you might be able to do it with a regex, but have some pity of the guy maintaining it behind you. :)
I'll assume you are simply disallowing all non-alphas. You sure you don't want to automatically downcase it too? And as an aside, this will disallow extended characters, and firstname.lastname is a very euro-centric mindset...
declare -l username # forces values to lowercase
msg="Please use only letters with a single dot separator, and limit the total to 16 characters."
while read -p "Enter a Username (firstname.lastname): " username
do case "$username" in # check for
# too long | invalid chars | multidots
?????????????????*|*[^a-z.]*|*.*.*) echo "$msg" ;; # add A-Z if not downcasing
*.*) break;; # this is the format we want
*) echo "$msg" ;; # a catch-all in case we missed anything else
esac
done
Regexes are more powerful than globbing, but this is more readable to me. YMMV.
While Read Line - Limit Number of Lines
There are some ways to meet your requirements:
Method 1
Use head
to display first few lines of a file.
head -n 2 order.csv | while read line;
do
order=$(echo $line | cut -d "," -f 1)
status=$(echo $line | cut -d "," -f 3)
echo "$order:$status"
done
Method 2
Use a for loop.
for i in {1..2}
do
read line
order=$(echo $line | cut -d "," -f 1)
status=$(echo $line | cut -d "," -f 3)
echo "$order:$status"
done < order.csv
Method 3
Use awk
.
awk -F, 'NR <= 2 { print $1":"$3 }' order.csv
Bash - getting MAX value from a list of integers
Your loops are a bit wonky (technical term) and you are resetting maxLength
to zero on every iteration of your loop. You want something a bit more like:
#!/bin/bash
fn="${1:-/dev/stdin}" ## read from file given as 1st argument (default stdin)
test -r "$fn" || { ## validate file is readable
printf "error: file not readable '%s'.\n" "$fn"
exit 1
}
declare -i maxlength=0 ## set maxlength before loop
maxname=
while IFS=, read -r area name host
do
test -n "$name" || continue ## if name not set get next line
len=${#name}
if [ "$len" -gt "$maxlength" ]; then ## test length against max
maxlength=$len ## update max if greater
maxname="$name" ## save name in maxname
fi
done <"$fn" ## feed loop by redirecting file
printf "maxname: %s (len: %d)\n" "$maxname" "$maxlength"
Example Use/Output
$ bash maxnm.sh <dat/maxnm.txt
maxname: script_name_12345678999999 (len: 26)
Look things over and let me know if you have further questions.
Related Topics
X86 Linux Assembler Get Program Parameters from _Start
How to Add Chromedriver to Path in Linux
How to Use Both 64 Bit and 32 Bit Instructions in the Same Executable in 64 Bit Linux
Url Encoding a String in Bash Script
Redirecting Output to a File in C
Can't Run Sonar Server Caused by Elasticsearch Cannot Running as Root
/Usr/Bin/Ld: Skipping Incompatible Foo.So When Searching for Foo
Capture Both Exit Status and Output from a System Call in R
How to Disable or Change the Timeout Limit for the Gpu Under Linux
How Does Execve Call Dynamic Linker/Loader (Ld-Linux.So.2)
Shell Script Get Ctrl+Z with Trap
Does Cron Expression in Unix/Linux Allow Specifying Exact Start and End Dates
How to Handle the Linux Socket Revents Pollerr, Pollhup and Pollnval