converting number to bitfield string in bash - bash

What might be the most concise way in bash to convert a number into a bitfield character string like 1101?
In effect I am trying to do the opposite of
echo $[2#1101]
Why: I need to send a parameter to a program that takes bitfields in the form of a full string like "0011010110" but often only need to enable one or few bits as in:
SUPPRESSbits=$[1<<16] runscript.sh # OR
SUPPRESSbits=$[1<<3 + 1<<9] runscript.sh # much more readable when I know what bits 3 and 9 toggle in the program
Then runscript.sh then sees in its env a SUPPRESSbits=65536 rather than SUPPRESSbits="1000000000000000" and ends in parse error.

The easy way:
$ dc <<<2o123p
1111011
$ bc <<<'obase=2; 123'
1111011

I doubt about bash but you always can use perl:
a=123; b=$(perl -e 'printf "%b", "'$a'"'); echo $b
1111011

Related

How to move and rename a file with random characters in shell?

I have this file:
/root/.aria2/aria2.txt
and I want to move it to:
/var/spool/sms/outgoing/aria2_XXXXX
Note that XXXXX are random characters.
How do I do that using only the facilities exposed by the openwrt (a GNU/Linux distribution for embedded devices) and the ash shell?
A simple way of generating a semi-random number in bash is to use the date +%N command or the system provided $RANDOM:
rn=$(date +%N) # Nanoseconds
rn=${rn:3:5} # to limit to 5 digits
or, using $RANDOM, you need to check you have sufficient digits for your purpose. If 5 is the number of digits you need:
rn=$RANDOM
while [ ${#rn} -lt 5 ]; do
rn="${rn}${RANDOM}"
done
rn=${rn:0:5}
To move while providing the random suffix:
mv /root/.aria2/aria2.txt /var/spool/sms/outgoing/aria2_${rn}
On systems with /dev/random you can obtain a string of random ASCII characters with something like
dd if=/dev/random count=1 |
tr -dc ' -~' |
dd bs=8 count=1
Set the bs= in the second instance to the amount of characters you want.
The probability of getting the same result twice is very low, but you have not told us what is an acceptable range. You should understand (or help us help you understand) what is an acceptable probability in your scenario.
Use the tempfile command
mv aria2.txt `tempfile -d $dir -p aria2`
see man tempfile for the gory details.

How to store hex value in shellscript

I am new to shellscript
I have this program
for(( s=0x001; s <=0x00f; s++))
do
echo $s
done
I want to print s values as 1,2,3,4.....a,b,c,d,e,f
But when I run above program,I have seen the output as 1,2,3,4,5,6......13,14,15.
I want to print the hex values only.
How to pass hex values in pipe.Lets say I have to pass this hex in pipe along with some other arguments.How to do that?
Lets says I have to pass some arguments to access device driver in pipe.
echo "8 $s q" | /usr/sbin/tejas/test /dev/slot$1/tupp_fpga$devNo | grep "at offset"
Here s should contain hex values.How to do it.
I think printf "%x" $s should do. It is part of the POSIX standard, and implemented as a built-in command in bash:
$ type printf
printf is a shell builtin
…so the documentation can be found in man bash, at least for the Bash shell.
Use the printf command. It's standard and works more or less like the C function.
printf "%x\n" $s
I'm not quite sure to understand the updated question but...
... if you require the given format, something like that will do the job:
print "8 %x q" $s | /usr/sbin/tejas/test /dev/slot$1/tupp_fpga$devNo | grep "at offset"
If your not familiar with the printf-style functions please refer to one of the many web pages describing the various format available.
On this particular case, the %x in the format string will be replaced by the hexadecimal representation of the next argument. Given that the s variable hold the value 1010 (or 0xA16 or 0138 -- which are indeed the same), the printf internal command will write the string 8 a s to the standard input of your /usr/sbin/tejas/test tool.

Convert from base6 to base64 in Bash

I don't know much programming and have tried to find an answer, but have trouble finding anything even related to base6. I am trying to write a bash script to take a string of dice rolls and convert it to a base64 password.
I've tried
echo 13545142010250324013240412300102 |base64
but I get weird outputs such as
MTM1NDUxNDIwMTAyNTAzMjQwMTMyNDA0MTIzMDAxMDIK
or
MTM0MTIzNDM1MzQwMTIwNDMxMjQxCg==
which is not uniformly distributed.
What am I missing?
The base64 command expects binary input. Your base-6 string is not uniformly distributed on the set of characters that base64 accepts, therefore the output will also follow a severely restricted distribution.
One possibility: convert your number in radix 64 using bc and then convert each "digit" of this number into a character:
#!/bin/bash
pool=( {A..Z} {a..z} {0..9} + / )
shopt -s extglob
die() { (($#)) && printf >&2 '%s\n' "$#"; exit 1; }
[[ $1 = +([012345]) ]] || die "bad argument"
for i in $(BC_LINE_LENGTH=0 bc <<< "obase=${#pool[#]}; ibase=6; $1"); do
printf '%s' "${pool[10#$i]}"
done
printf '\n'
I called this script banana, I chmod +x banana and then:
$ ./banana 13545142010250324013240412300102
HSr/X8Hn0oUGFG
You can safely change the elements of pool: modify, add or remove elements in there, the new radix is automatically taken into account, since we used obase=${#pool[#]}, as long as there are at least 17 elements in pool.
Note. I'm using BC_LINE_LENGTH=0 to disable bc's output multi-line feature. If not available on your system, you'll have to handle trailing backslashes. The adaptation is straightforward and left as an exercise to the reader.

Adding and dividing variables in bash. error: TEST3=: command not found

SO I am making a program that tests the average REad/Write speed of the hard drive using the dd command and my code is as follows(bash):
a=1
b=1
numval=3
for i in `seq 1 3`;
do
TEST$i=$(dd if=/dev/zero of=speedtest bs=1M count=100 conv=fdatasync)
#I think that this is the problem line
done
RESULT=$(($TEST1 + $TEST2))
RESULT=$(($RESULT + $TEST3))
RESULT=$(($RESULT / $numval))
echo $RESULT > Result
The code above returns the following errors (in between the dd outputs):
TEST1=: command not found
TEST2=: command not found
TEST3=: command not found
Please help (believe it or not) this is for a school project
edit: I understand that my variable does not have a valid name. but Im wondering if there is a way to do this without this shit: "^$({$-%})$" REGEX? is there way to do it without that?
You have (at least) two problems.
TEST$i=... is not valid bash syntax for a variable assignment. And if the first "word" in a command line is not a valid assignment, then it's treated as a command name. So bash goes ahead and substitutes the value of $i for $i and the output of the dd command for $(dd ...) (see below), ending up with the successive "commands" TEST1=, TEST2= and TEST3=. Those aren't known commands, so it complains.
In an assignment, the only characters you can put before the = are letters, numbers and _ (unless it is an array assignment), which means that you cannot use parameter substitution to create a variable name. (But you could use an array.)
You seem to be assuming that the dd command will output the amount of time it took, or something like that. It doesn't. In fact, it doesn't output anything on stdout. It will output several lines on stderr, but stderr isn't captured with $(...)
First problem: you can't use a variable name that's defined in terms of other variables (TEST$i=...) without jumping through some special hops. There are several ways around this. You could use the declare command (declare TEST$i=...), or use an array (TEST[i]=... and then e.g. RESULT=$((TEST[1] + TEST[2]))), or what I'd recommend: accumulate the times as you go without bothering with the numbered TEST1 etc variables:
numval=3
result=0
for i in `seq 1 $numval`; do
test=$(dd if=/dev/zero of=speedtest bs=1M count=100 conv=fdatasync)
result=$((result + test))
done
result=$((result / numval))
(Note that I prefer to use lowercase variable names in shell scripts, to avoid accidentally using one of the shell's predefined variables and making a mess. Also, inside $(( )), variables are automatically replaced, so you don't need $ there.)
However, this still won't work because...
Second problem: dd doesn't output a number. In fact, it doesn't output anything to standard output (which $( ) captures). What it does is output a bunch of numbers and other such things to standard error. Your version of dd is a bit different from mine, but its stderr output is probably something like this:
$ dd if=/dev/zero of=/dev/null bs=1m count=100
100+0 records in
100+0 records out
104857600 bytes transferred in 0.011789 secs (8894645697 bytes/sec)
... and you presumably want to pick out the bytes/sec figure. Depending on your dd's exact output, something like this might work:
$ dd if=/dev/zero of=/dev/null bs=1m count=100 2>&1 | sed -n 's/^.*(\([0-9]*\) bytes.*$/\1/p'
8746239457
What this does is redirect dd's error output to standard output (2>&1), then pipe (|) that to a somewhat messy sed command that looks for something matching "(", then a bunch of digits, then " bytes", and outputs just the digits part.
Here's the full script I wind up with:
#!/bin/bash
numval=3
result=0
for i in `seq 1 $numval`; do
test=$(dd if=/dev/zero of=speedtest bs=1M count=100 conv=fdatasync 2>&1 | sed -n 's/^.*(\([0-9]*\) bytes.*$/\1/p')
result=$((result + test))
done
result=$((result / numval))
echo "$result" >Result

Bash script using negative to cycle through

I'm trying to run a bash script that includes a nested for loop within which a variable should cycle through negative exponents, viz:
for ABPOW in {-11..-9}
do
ABC = $((10**$ABPOW))
for ABCOEFF in {1..9}
do
sed -e 's/ACOEFF/'$ABC'/'\
This is only the inner two for loops of the code. When the values in the first bracket (for ABPOW) are positive, the code runs fine. However, when I have them as i do above, which is what I need, the error communicated to screen is:
./scripting_test2.bash: line 30: 10**-11: exponent less than 0 (error token is "1")
How do I make this run? Thanks in advance.
PS: I tried putting a negative sign in front of $ABPOW but the exponents are still recorded as positive.
Bash does not support floating point arithmetic (which is necessary for raising something into a negative power). Instead, you should use the bc utility.
ABC=$(bc -l <<< "10 ^($ABPOW)")
Also, there should be no spaces before and after the = in variable assignments
Here's another way:
perl -e 'for $abpow (-11..-9) { $abc=10**$abpow; for (1..9) { system("echo $abc"); } }'
Bash doesn't support floating point data types.
$ man bash|grep -c -i float
0
Do you have python installed?
ABC=$( python -c "print 10**$ABPOW" )
One alternative is to use awk for your complete script that has full support for floating point arithmetic:
awk 'BEGIN{for(i=-11; i<=-9; i++) {ABC=10^i; print ABC}}'
1e-11
1e-10
1e-09

Resources