I want to create a text file using bash shell in the following
+9990000001
+9990000002
+9990000003
+9990000004
...
The first four chars/digits are fixed (+999) and the other 7 digits starts from 0000001 to 9999999
I have the following code but it does not do 00000000 padding.
startnum=0;
endnum=9999999;
for (( i=$startnum; i<=$endnum; i++ )) ; do
echo $i ;
done
How would I also do the prefix +999?
You need to use printf to pad 0s:
startnum=1
endnum=9999999
for (( i=startnum; i<=endnum; i++ )) ; do
printf "+999%07d\n" $i
done
Output:
+9990000001
+9990000002
+9990000003
+9990000004
+9990000005
+9990000006
...
You can write:
startnum=90000000
endnum=99999999
for (( i = startnum; i <= endnum; i++ )) ; do
echo +99$i
done
(I would have suggested simply putting all three nines at the beginning, but 1010−1 is outside the range of 32-bit signed integers, so I'm not sure the arithmetic part would work.)
My version:
seq -f "+%10.0f" 9990000001 9999999999
or
seq -f "+999%07.0f" 9999999
Related
How to generate 9 digit random number in shell?
I am trying something like this but it only gave numbers below 32768.
#!/bin/bash
mo=$((RANDOM%999999999))
echo "********Random"$mo
Please help
output should be ********Random453351111
In Linux with /dev/urandom:
$ rnd=$(tr -cd "[:digit:]" < /dev/urandom | head -c 9) && echo $rnd
463559879
I think this should make it
shuf -i 99999999-999999999 -n 1
As a work around, we could just simply ask for 1 random integer, for n times:
rand=''
for i in {1..9}; do
rand="${rand}$(( $RANDOM % 10 ))"
done
echo $rand
Try it online!
Note [1]: Since RANDOM's upper limit has a final digit of 7, there's a slightly lesser change for the 'generated' number to contain 8 or 9's.
Because of RANDOM's limited range, it can only be used to retrieve four base-10 digits at a time. Thus, to retrieve 9 digits, you need to call it three times.
If we don't care much about performance (are willing to pay process substitution costs), this may look like:
#!/usr/bin/env bash
get4() {
local newVal=32768
while (( newVal > 29999 )); do # avoid bias because of remainder
newVal=$RANDOM
done
printf '%04d' "$((newVal % 10000))"
}
result="$(get4)$(get4)$(get4)"
result=$(( result % 1000000000 ))
printf '%09d\n' "$result"
If we do care about performance, it may instead look like:
#!/usr/bin/env bash
get4() {
local newVal=32768 outVar=$1
while (( newVal > 29999 )); do # avoid bias because of remainder
newVal=$RANDOM
done
printf -v "$outVar" '%04d' "$((newVal % 10000))"
}
get4 out1; get4 out2; get4 out3
result="${out1}${out2}${out3}"
result=$(( result % 1000000000 ))
printf '%09d\n' "$result"
Use perl, as follows :
perl -e print\ rand | cut -c 3-11
Or
perl -MPOSIX -e 'print floor rand 10**9'
Explaining my algorithm:
I'm trying to find out whether My current job for e.g. Write(W) is the same as my previous job, if my current job (W) is the same as my previous job (W) then check whether there's 1 integer of difference between them, for e.g. if the previous job was W9 and my current job is either W8 or W10, then append 0 to my seek array.
I've tried almost every way I could find on the internet to compare integers but none of them work, I continue to receive an invalid arithmetic syntax error when trying to compare current and previous job.
Any ideas?
# Jobs
lastJob=""
currentJob=""
lastNumber=0
currentNumber=0
# Arrays
seek=()
RW=()
shift 3
# Reads final into array
while IFS= read -r line
do
Job+=($line)
done < ./sim.job
#-----------------------------------
# Single HDD Algorithm
#-----------------------------------
for (( i=0; i<=${#Job[#]}; i++ ));
do
currentString="${Job[$i]}"
currentJob=${currentString:0:1}
currentNumber=${currentString:1:3}
if [[ $currentJob == $lastJob ]]
then
if [[ $currentNumber -eq $lastNumber-1 ]] || [[ $currentNumber -eq $lastNumber+1 ]]
then
seek+=(0)
RW+=(60)
else
seek+=(5)
RW+=(60)
fi
else
seek+=(5)
RW+=(60)
fi
lastString="${Job[$i]}"
lastJob=${lastString:0:1}
lastNumber=${currentString:1:3}
done
This prints output:
#-----------------------------------
# Print Information
#-----------------------------------
for (( i=0; i<${#Job[#]}; i++ ));
do
echo -e "${Job[$i]}:${seek[$i]}:${RW[$i]}"
done
Expected Output:
R9:5:60
W9:5:60
W10:0:60
R11:0:60
R13:5:60
R18:5:60
R19:0:60
R20:0:60
R21:0:60
Actual Output:
") syntax error: invalid arithmetic operator (error token is "
R9:5:60
W9:5:60
W10::
R11::
R13::
R18::
R19::
R20::
R21::
sim.job file (Input):
R9
W9
W10
R11
R13
R18
R19
R20
R21
rogue \r were found in my input file, to solve this I used the commands:
To check if \r are in the file: od -c <filename> | tr ' ' '\n' | grep '\r'
To remove rogue \r use: tr -d '\r' < filename
Thanks again #mark-fuso
Taking count from file, say if count = 5, I want to print 5 variables. i.e. A B C D E.
If count = 2, Print 2 variables A B, etc.
I have tried using the ASCII values but couldn't go through it.
for i in {1..5}; do
count=5; a=0;
printf "\x$(printf %x '65+$a')";
count=count+1;
done
if count = 5, I want to print 5 variables. i.e. A B C D E. If count = 2, Print 2 variables A B, etc.
Here's a program that matches your style that does what you are looking for:
a=0
for i in {1..5}; do
printf "\x$(printf %x $(( 65 + a )) )";
a=$((a+1));
done
The first thing to note is that in order to do math in bash, you'll need to use the $(( )) operation. Above, you can see I replaced you '65+$a' with $(( 65 + a )) . That's the big news that you need to get math done.
There were a couple of other little issues, but you were stuck on the $(()) stuff so they weren't clear yet. Incidentally, the 'a' variable can be completely removed from the program to just use the 'i' variable like this:
for i in {1..5}; do
printf "\x$(printf %x $(( 64 + i )) )";
done
I had to change the constant to 64 since we are now counting starting at 1.
The {1..5} expression is a good short cut for 1 2 3 4 5, but you won't be able to put a variable into it. So, if you need to add a count variable back in, consider using the seq program instead like this:
count=$1
for i in $(seq 1 $count); do
printf "\x$(printf %x $(( 64 + i )) )";
done
Note that $() is different than the math operator $(()). $() runs a subcommand returning the results.
method 1: simple brace expansion
#!/bin/bash
# generate a lookup table
vars=( - $(echo {A..Z}) )
# use the elements
for i in {1..5}; do
echo ${vars[$i]}
done
{A..Z} generates 26 strings: A, B, ..., Z
which get stored in an array variable by vars=(...)
we prepend a - that we'll ignore
we can then do 1-based indexing into the array
limited to 26 variables (or whatever range we choose)
method 2: multiple brace expansion to generate arbitrary long variables
#!/bin/bash
if [[ ! $1 =~ ^[0-9]+$ ]]; then
echo "Usage: $0 count"
exit
fi
cmd='{A..Z}'
for (( i=$1; i>26; i=i/26 )); do
cmd="${A..Z}$cmd"
done
vars=( $(eval echo $cmd) )
for (( i=0; i<$1; i++ )); do
echo ${vars[$i]}
done
i/26 does integer division (throws away the remainder)
I'm lazy and generate "more than enough" variables rather than attempting to calculate how many is "exactly enough"
{a..b}{a..b}{a..b} becomes aaa aab aba abb baa bab bba bbb
using eval lets us do the brace expansion without knowing in advance how many sets are needed
Sample output:
$ mkvar.sh 10000 |fmt -64 | tail -5
ORY ORZ OSA OSB OSC OSD OSE OSF OSG OSH OSI OSJ OSK OSL OSM
OSN OSO OSP OSQ OSR OSS OST OSU OSV OSW OSX OSY OSZ OTA OTB
OTC OTD OTE OTF OTG OTH OTI OTJ OTK OTL OTM OTN OTO OTP OTQ
OTR OTS OTT OTU OTV OTW OTX OTY OTZ OUA OUB OUC OUD OUE OUF
OUG OUH OUI OUJ OUK OUL OUM OUN OUO OUP
I am iterating over hex digits in a string using a for loop. I can extract each hex digit ok, but my code to convert to a number is giving strange values. How can I fix this code?
Script:
#!/bin/bash
mystring="5e51584a4c"
for (( i = 0; i < ${#mystring}; i = i + 2)); do
snumber="${mystring:i:2}"
printf "number as string=%s\n" $snumber
number=$(printf "%x" "'${mystring:i:2}")
printf "number=%d\n" $number
done
I am getting this output:
number as string=5e
number=35
number as string=51
number=35
number as string=58
number=35
number as string=4a
number=34
number as string=4c
number=34
You don't need printf in this case, you can use bash's $((base#number)) construct.
#!/bin/bash -
mystring="5e51584a4c"
for ((i=0; i<${#mystring}; i+=2)); do
snumber="${mystring:i:2}"
echo "number as string=${snumber}"
echo "number=$((16#${snumber}))"
done
Hex numbers need to have 0x prefix:
printf "%d\n" 0x5e
Outputs:
94
mystring="5e51584a4c"
for (( i = 0; i < ${#mystring}; i = i + 2)); do
snumber="${mystring:i:2}"
printf "number=%d\n" 0x$snumber
done
Your printf command is printing the character code of the first digit in each substring, because you have the ' prefix to the argument. You want a 0x prefix instead.
When printing as hexadecimal, you can use %#x conversion to make printf emit the leading 0x prefix needed by the next usage:
number=$(printf '%#x' "0x${mystring:i:2}")
# ^^^ ^^
I have a homework assignment that is asking to shift a decimal number by a specified amount of digits. More clearly this bash script will take two input arguments, the first is the number(maximum 9 digits) that the shift will be performed on and the second is the number(-9 to 9) of digits to shift. Another requirement is that when a digit is shifted off the end, it should be attached to the other end of the number. One headache of a requirement is that we cannot use control statements of any kind: no loops, no if, and switch cases.
Example: 12345 3 should come out to 345000012 and 12345 -3 should be 12345000
I know that if I mod 12345 by 10^3 I get 345 and then if I divide 12345 by 10^3 I get 12 and then I can just concatenate those two variables together to get 34512. I am not quite sure if that is exactly correct but that is the closest I can get as of now. As far as the -3 shift, I know that 10^-3 is .001 and would work however when I try using 10^-3 in bash I get an error.
I am just lost at this point, any tips would be greatly appreciated.
EDIT: After several hours of bashing (pun intended) my head against this problem, I finally came up with a script that for the most part works. I would post the code right now but I fear another student hopelessly lost might stumble upon it. I will check back and post what I came up with in a week or two. I was able to do it with mods and division. Thank you all for the responses, it really helped me to open up and think about the problem from different angles.
Here's a hint:
echo ${string:0:3}
echo ${#string}
Edit (2011-02-11):
Here's my solution. I added some additional parameters with defaults.
rotate-string ()
{
local s=${1:-1} p=${2:--1} w=${3:-8} c=${4:-0} r l
printf -vr '%0*d' $w 0 # save $w zeros in $r
r=${r//0/$c}$s # change the zeros to the character in $c, append the string
r=${r: -w} # save the last $w characters of $r
l=${r: -p%w} # get the last part of $r ($p mod %w characters)
echo "$l${r::w-${#l}}" # output the Last part on the Left and the Right part which starts at the beginning and goes for ($w minus the_length_of_the_Left_part) characters
}
usage: rotate-string string positions-to-rotate width fill-character
example: rotate-string abc -4 9 =
result: ==abc====
Arguments can be omitted starting from the end and these defaults will be used:
fill-character: "0"
width: 8
positions-to-rotate: -1
string: "1"
More examples:
$ rotate-string
00000010
$ rotate-string 123 4
01230000
Fun stuff:
$ for i in {126..6}; do printf '%s\r' "$(rotate-string Dennis $i 20 .)"; sleep .05; done; printf '\n'
$ while true; do for i in {10..1} {1..10}; do printf '%s\r' "$(rotate-string : $i 10 .)"; sleep .1; done; done
$ while true; do for i in {40..2} {2..40}; do printf '%s\r' "$(rotate-string '/\' $i 40 '_')"; sleep .02; done; done
$ d=0; while true; do for i in {1..10} {10..1}; do printf '%s\r' "$(rotate-string $d $i 10 '_')"; sleep .02; done; ((d=++d%10)); done
$ d=0; while true; do for i in {1..10}; do printf '%s\r' "$(rotate-string $d $i 10 '_')"; sleep .2; ((d=++d%10)); done; done
$ shape='▁▂▃▄▅▆▇█▇▆▅▄▃▂▁'; while true; do for ((i=1; i<=COLUMNS; i++)); do printf '%s\r' "$(rotate-string "$shape" $i $COLUMNS ' ')"; done; done
In the absence of control structures, you need to use recursion, with index values as "choice selections", which is how functional programming often works.
#!/bin/sh
#
# cshift NUMBER N
cshift() {
let num=10#$1
num=`printf '%09d' $num`
lshift="${num:1:8}${num:0:1}"
rshift="${num:8:1}${num:0:8}"
next=( "cshift $lshift $(($2 + 1))" "echo $num" "cshift $rshift $(( $2 - 1 ))" )
x=$(( $2 == 0 ? 1 : $2 < 0 ? 0 : 2 ))
eval "${next[x]}"
}
cshift $1 $2
and, the testing:
$ for ((i=-9;i<=9;i++)); do cshift 12345 $i ; done
000012345
500001234
450000123
345000012
234500001
123450000
012345000
001234500
000123450
000012345
500001234
450000123
345000012
234500001
123450000
012345000
001234500
000123450
000012345
You can also do some math on the indexes and avoid the recursion, but I don't mind making the computer work harder so I don't have to. It's easy to think of how to do the shift by one in either direction, and then I use an evaluated choice that is selected by the signum of the shift value, outputting a value and stopping when the shift value is zero.