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.
Related
Hello Amazing Stack Overflow People,
I'm stuck on storing values that are returned when using a CLI tool in my bash script, my goal to automate a number of commands I have to run each time I set up new devices for a customer. I'm pretty much having to do this on every product, and want to create a script to automate the routine.
#!/bin/bash
particle usb start-listening
RESULT=$(particle serial identify $OUTPUT)
if [ $? -eq 0 ]; then
printf '%s\n' "$RESULT"
else
printf '%s\n' "No Match"
fi
This returns this text to the terminal
Your device id is e00fce681fffffffffc08949b
Your IMEI is 352999999084606
Your ICCID is 8901413111111117667
Your system firmware version is 1.5.0
My goal is to store the device id and the ICCID to then use in the next few particle-CLI commands.
Like this curl request that activates the sim card,
curl -X PUT https://api.particle.io/v1/sims/<$ICCID> \
-d action=activate \
-d access_token=<$ACCESS_TOKEN>
and adding the device to our account for testing
particle device add <device_id>
I've spent the morning trying different tutorials and commands to parse the return data from the first command and store the devcie_ID and the ICCID to no avail.
I've tried awk:
read deviceId IMEI ICCID <<< $("particle serial identify" | awk '/is[[:space:]]/ { print $2 }')
I've tried IFS=' ':
IFS=' '
read -r first second third fourth fifth sixth seven eight night ten eleven twelve thirten fourten fiften sizten seventen <<< "$RESULT"
read -a strarr <<< "$RESULT"
for val in "${strarr[#]}";
do
echo "$strarr\n"
done
I've never written a bash script before so any help pointing to better documentation on how to do this, I'm happy to read and learn. I just don't think I completely understand how bash handles Strings yet and have not found any documentation that explains what going on.
I'm hoping someone with more experience in bash scripting can point me in the right direction.
At some point, when I have more want to write a Node program to handle the setting up and testing each device during manufacturing, I'm also interested in learning how to create a Go CLI tool to manage our devices in the future.
I'm not even sure if what I'm trying to accomplish can be done with just a bash script.
Cheers,
N
First, some general scripting recommendations: It's safest to use lower- or mixed-case variable names (e.g. result or Result instead of RESULT), to avoid conflicts with the various all-caps names that have special meanings or functions. Run your scripts through shellcheck.net, as it's good at spotting common scripting mistakes. And if you're trying to debug a script, add the command set -x before the trouble section to get an execution trace of what's happening (and set +x after it, to turn off tracing).
As for extracting relevant info from a string like this: there are a number of ways to do it, all a bit clunky, and which one to use is mostly a matter of personal preference. In this situation, I'd tend to use sed to extract the relevant bits:
deviceID=$(sed -n 's/^[[:space:]]*Your device id is //p' <<<"$result")
iccid=$(sed -n 's/^[[:space:]]*Your ICCID is //p' <<<"$result")
Explanation: sed normally passes through all input (after it's modified), but -n tells it not to pass anything through (i.e. "print" it) unless explicitly told to. s/^[[:space:]]*Your device id is //p tells it to replace some spaces followed by "Your device id is " with the empty string, and then print the result; since that leaves just the device id (and the "print the result" only happens on the line where the substitution happened), it prints just the device id.
You could do it just as well with awk:
deviceID=$(awk '/Your device id is / {print $NF}' <<<"$result")
iccid=$(awk '/Your ICCID is / {print $NF}' <<<"$result")
Here the /Your device id is / means "on lines matching this string" and {print $NF} prints the last (space-delimited) field on the line.
Yet another method is to use bash's built-in variable trimming modifiers:
tempString=${result#*Your device id is }
deviceID=${tempString%%$'\n'*}
tempString=${result#*Your ICCID is }
iccid=${tempString%%$'\n'*}
Here, the #*Your ICCID is modifier to the variable expansion removes from the beginning of the string (#) through (*) the string "Your ICCID is ", and then %%$'\n'* removes from the end (%%) to a newline (the double-%% makes it remove as much as possible, i.e. starting at the first, rather than last, newline character). See here for more info about these (and other) modifiers.
BTW, when you get the RESULT string, you use the command particle serial identify $OUTPUT. What is $OUTPUT? the variable doesn't appear to be set to anything, so (since it's not double-quoted) it'll just vanish from the command. Is that intentional?
You can save output of command to variable file and parse necessery variables
file=$(particle serial identify $OUTPUT)
device_id=$(echo $file| grep -Eo 'device id is .+?$' |sed 's/device id is //g')
ICCID=$(echo $file| grep -Eo 'ICCID is .+?$' |sed 's/ICCID is //g')
echo $device_id
echo $ICCID
Here is my script:
d1=0.003
d2=0.0008
d1d2=$((d1 + d2))
mean1=7
mean2=5
meandiff=$((mean1 - mean2))
echo $meandiff
echo $d1d2
But instead of getting my intended output of:
0.0038
2
I am getting the error Invalid Arithmetic Operator, (error token is ".003")?
bash does not support floating-point arithmetic. You need to use an external utility like bc.
# Like everything else in shell, these are strings, not
# floating-point values
d1=0.003
d2=0.0008
# bc parses its input to perform math
d1d2=$(echo "$d1 + $d2" | bc)
# These, too, are strings (not integers)
mean1=7
mean2=5
# $((...)) is a built-in construct that can parse
# its contents as integers; valid identifiers
# are recursively resolved as variables.
meandiff=$((mean1 - mean2))
Another way to calculate floating numbers, is by using AWK rounding capability, for example:
a=502.709672592
b=501.627497268
echo "$a $b" | awk '{print $1 - $2}'
1.08218
In case you do not need floating point precision, you may simply strip off the decimal part.
echo $var | cut -d "." -f 1 | cut -d "," -f 1
cuts the integer part of the value. The reason to use cut twice is to parse integer part in case a regional setting may use dots to separate decimals and some others may use commas.
Edit:
Or, to automate the regional settings one may use locale.
echo $var | cut -d $(locale decimal_point) -f 1
You can change the shell which you are using. If you are executing your script with bash shell bash scriptname.sh try using ksh for your script execution. Bash doesn't support arithmetic operations that involve floating point numbers.
Big shout-out to the bc command - it totally saved my day! It's a simple answer, but it worked like a charm.
a=1.1
b=1.1
echo $a + $b | bc -l
# Output:
2.2
#SUM
sum=$(echo $a + $b | bc -l)
echo $sum
# Output
2.2
bc is a command-line calculator, which allows users to perform mathematical calculations on the terminal.
This question already has answers here:
How do I iterate over a range of numbers defined by variables in Bash?
(20 answers)
Closed 3 years ago.
I am still learning how to shell script and I have been given a challenge to make it easier for me to echo "Name1" "Name2"..."Name15" and I'm not too sure where to start, I've had ideas but I don't want to look silly if I mess it up. Any help?
I haven't actually tried anything just yet it's all just been mostly thought.
#This is what I wrote to start
#!/bin/bash
echo "Name1"
echo "Name2"
echo "Name3"
echo "Name4"
echo "Name5"
echo "Name6"
echo "Name7"
echo "Name8"
echo "Name9"
echo "Name10"
echo "Name11"
echo "Name12"
echo "Name13"
echo "Name14"
echo "Name15"
My expected results are obviously just for it to output "Name1" "Name2" etc. But I'm looking for a more creative way to do it. If possible throw in a few ways to do it so I can learn. Thank you.
The easiest (possibly not the most creative) way to do this is to use printf:
printf "%s\n" name{1..15}
This relies on bash brace expansion {1..15} to have the 15 strings.
Use a for loop
for i in {1..15};do echo "Name$i";done
A few esoteric solutions, from the least to the most unreasonable :
base64 encoded string :
base64 -d <<<TmFtZTEKTmFtZTIKTmFtZTMKTmFtZTQKTmFtZTUKTmFtZTYKTmFtZTcKTmFtZTgKTmFtZTkKTmFtZTEwCk5hbWUxMQpOYW1lMTIKTmFtZTEzCk5hbWUxNApOYW1lMTUK
The weird chain is your expected result encoded in base64, an encoding generally used to represent binary data as text. base64 -d <<< weirdChain is passing the weird chain as input to the base64 tool and asking it to decode it, which displays your expected result
generate an infinite stream of "Name", truncate it, use line numbers :
yes Name | awk 'NR == 16 { exit } { printf("%s%s\n", $0, NR) }'
yes outputs an infinite stream of what it's passed as argument (or y by default, used to automatize interactive scripts asking for [y/n] confirmation). The awk command exits once it reaches the 16th line, and otherwise prints its input (provided by yes) followed by the line number. The truncature could as easily be done with head -15, and I've tried using the nl "number line" utility or grep -n to number lines, but they always added the line numbers as prefix which required an extra re-formatting step.
read random binary data and hope to stumble on all the lines you want to output :
timeout 1d strings /dev/urandom | grep -Eo "Name(1[0-5]|[1-9])" | sort -uV
strings /dev/urandom will extract ascii sequences from the binary random source /dev/urandom, grep will filter those which respect the format of a line of your expected output and sort will reorder those lines in the correct order. Since sort needs to have a received its whole input before it reorders it and /dev/urandom won't stop producing data, we use timeout 1d to stop reading from /dev/urandom after a whole day in hope it has sifted through enough random data to find your 15 lines (I'm not sure that's even remotely likely).
use an HTTP client to retrieve this page, extract the bash script you posted and execute it.
my_old_script=$(curl "https://stackoverflow.com/questions/57818680/" | grep "#This is what I wrote to start" -A 18 | tail -n+4)
eval "$my_old_script"
curl is a command line tool that can be used as an HTTP client, grep with its -A 18 parameter will select the "This is what I wrote to start" text and the 18 lines that follow, tail will remove the first 3 lines, and eval will execute your script.
While it will be much more efficient than the previous solution, it's an even less reasonable solution because high-rep users can edit your question to make this solution execute arbitrary code on your computer. Ideally you'd be using an HTML-aware parser rather than basic string manipulation to extract the code, but we're not talking about best practices here...
In Shell scripting (Linux/Ubuntu , Bash) , why do we use echo and bc commands together ? I am new to Shell scripting and have a basic understanding of pipes .
I know that bc is kind of a seperate language . How does the following statement actually work (Just an example) ?
echo 5+6 | bc
The first command (echo) writes the expression "5+6" to its standard output. This is then piped to bc's standard input, read from there, and evaluated.
This is used since bc doesn't take the expression as a direct input, it always reads from files and/or standard input.
You can use that program combination for another set of powerful operations, for example you can convert from hexadecimal to binary like this
echo "ibase=16; obase=2; A15" | bc
It will print: 101000010101
As for the process of echoing and using the | operator, it just make the output of the echocommand an input for the bc program, you can achieve the same using for example: bc <<< "5 + 2"
bc does not read operations from command line arguments, instead it reads it from an input file or in an interactive session
Another example of this useful combination is the calculation of really big quantities, like:
echo "2^1024" | bc
A note about the <<<: it passes a string on a single line as an input file to the command, if the program reads its input from a file, with <<< you can convert a string to a "file" and then pass this "file" to the program.
echo is not required here and can be replaced by an here document:
bc <<%
5+6
%
or with modern shells:
bc <<< 5+6
Before bc command we can see very simple PIPE:
|
The name pipe is very accurate! Like a normal pipe this one is transferring water from source to target. In computer science water is called data or information.
Like every good pipe, both endings of it are special. Through those endings we can connect pipe to other pipes, taps, joints, etc.
One ending of this pipe is connected to bc which has matching ending. Bc is a big piece of software, so it has many different connection points for different pipes. Also for this simple | pipe.
On the other hand 5+6 is not any piece of software. It is pure data/water. You can imagine what will happen if you pure water to one end of the pipe without fixed connection! Lack of water pressure...
We need some software which has good connection to that pipe. Echo is very simple application, doing practically nothing, like decent echo should do... But it has basic and functional ending matching that simple pipe.
A little bit of text formatting
echo -n "pi=" ; bc -l <<< "scale=10; 4*a(1)"
pi=3.1415926532
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