how to properly read from stream in bash - bash

I am reading from the shared memory a stream producing an infinite information output such as:
0x1 (TimeStamp) 12Bytes:11216 + 1771/(47999+1) (0.036896) delta= 0+ 1536/(47999+1) (0.032000) 11216.013361 23.534ms 2015.06.25 11:51:16.525
0x4 (ReferenceTime) 12Bytes:11215 + 24786286/(26999999+1) (0.918011) delta= 0+ 806359/(26999999+1) (0.029856) 11216.013376 -95.366ms 2015.06.25 11:51:16.525
0x6 (ProcessDelay) 4Bytes: 32 (0x20)
0x7 (ClockAccuracy) 8Bytes: offset=0.000ppm (+-0.000ppm)
0xb (ClockId) 8Bytes: 01 00 00 00 42 22 01 00
0x20001 (SampleRate) 4Bytes: 48000 (0xbb80)
0x20002 (Channels) 4Bytes: 6 (0x6)
0x20003 (PcmLevel) 24Bytes: -11041 -11541 -49076 -86121 -24846 -24382
0x20004 (PcmPeak) 24Bytes: -8088 -8697 -37244 -84288 -21437 -21769
0x2000e (DolbyDpMetadata) 39352Bytes:
Linear Time: 11216 + 1771/(47999+1) (0.036896) delta= 0+ 1536/(47999+1) (0.032000)
if i try to read the stream with the following command:
while read line;
do
echo "$line";
echo "im here!"
done < <(../tools/spucat adec-68)
wherespucat is a cpp binary exacutable that continuosly print out on console using printf() information about incoming data packets.
this is the result:
im here!
�k�G��E�x����b��h�������c����2��/n��-�U���QE�L�x���c�������������������������������x��4����O��M�����/��(������������������~��E�*�������;
im here!
������r��$�|��J�n�P�4�
if i start the script whit this command:
while read line;
do
echo "$line";
echo "im here!"
done < $(../tools/spucat adec-68)
it actually never go inside the while loop, just start to print out the stream whaiting for the end.
Is tehere a way to read it line by line and process it inside the while loop?

spucat is dumping to the standard error (no idea why), so to processing it must be redirect to the standard output:
while read -r line;
do
echo "$line";
echo "im here!"
done < <(../tools/spucat -p 4 adec-68 2>&1 > /dev/null)

Related

How to execute a condition based on a returned value using expect

I'm working on an expect script that will execute a condition based on the returned value from the hardware. I want to use expect to automate this process, however, I'm unsure if I'm going about doing this correctly as shown in the code below.
#! /bin/expect
set timeout 5
puts "Spawning serial connection"
spawn -open [open /dev/ttys1 w+]
send --"\r"
expect "barebox: /"
send --"?\r"
expect "barebox: /"
#I2C communication to initiate test pattern test
send "i2c_write -b 1 -a 0x50 -r 0x105 -w 0x02 0xf0\r"
expect "barebox: /"
send "i2c_write -b 1 -a 0x50 -r 0x105 -w 0x01 0xf0\r"
expect "barebox: /"
send "i2c_read -b 1 -a 0x50 -r 0x108 -w 0x03 0xh0\r"
#checking to see if value returned matches any of the following conditions
expect{
while{"0x04 0x00}{
put "FPGA still busy/r"
send "i2c_read -b 1 -a 0x50 -r 0x108 -w 0x03 0xh0\r"
}
if{"0x00 0x00}{
put "Test Pattern test successful\r"
}
elseif{"0x08 0x00}{
put "Test Pattern test failed\r"
}
}
put "End of Test Pattern test\r"
You can write your loop and test as:
expect {
"0x04 0x00" {
puts "FPGA still busy"
send "i2c_read -b 1 -a 0x50 -r 0x108 -w 0x03 0xh0\r"
exp_continue
}
"0x00 0x00" {
puts "Test Pattern test successful"
}
"0x08 0x00" {
puts "Test Pattern test failed"
}
}
It may be wise to have a delay in your loop so as not to hammer the remote system with continuous requests. E.g. you could wait 1 second each time by adding the line sleep 1 before the send. For full details see the docs at https://www.tcl-lang.org/man/expect5.31/expect.1.html

bash: parsing F-key (F1-F10) in script

I wrote a bash script, which has "buttons" similar to "mc" or Norton Commander. Right now, I use the number keys (1-0) to simulate the buttons being pressed. However, I would rather have the F-keys (F1-F10) to do it.
I saw this question and answers, but I am not certain this can be used in a script to trigger a function (e.g. by using "read").
Does bash support it? If so, is there a fairly easy way to implement it?
UPDATE
The script is kind of a dash, which needs to be refreshed in order to keep the contents current. However, at the same time I would like to keep the "channel" open to allow user input (therefore sleep would not be adequate).
The read line currently in use to get the user input looks like this:
read -n 1 -s -t "${iRefresh}" sReturnVar.
Here "iRefresh" is set to 2 seconds in order to time out when no input is given to refresh the display and return to the read line thereafter. In essence the read line doubles as a content refresher while waiting for user input.
This will dynamically determine the values for F1-F24, then use them in the context you're looking for. My system coopts F11, so I did not show that. This is somewhat brittle in that it depends on terminfo and sane terminal codes -- YMMV.
#!/usr/bin/env bash
read_key_press() {
if read -sN1 key_press; then
while read -sN1 -t 0.001 ; do
key_press+="${REPLY}"
done
fi
}
declare -a fnkey
for x in {1..24}; do
raw=$(tput kf$x | cat -A)
fnkey[$x]=${raw#^[}
done
while read_key_press; do
case "${key_press}" in
$'\e'${fnkey[1]}) echo 'F1';;
$'\e'${fnkey[2]}) echo 'F2';;
$'\e'${fnkey[3]}) echo 'F3';;
$'\e'${fnkey[4]}) echo 'F4';;
$'\e'${fnkey[5]}) echo 'F5';;
$'\e'${fnkey[6]}) echo 'F6';;
$'\e'${fnkey[7]}) echo 'F7';;
$'\e'${fnkey[8]}) echo 'F8';;
$'\e'${fnkey[9]}) echo 'F9';;
$'\e'${fnkey[10]}) echo 'F10';;
$'\e'${fnkey[11]}) echo 'F11';;
$'\e'${fnkey[12]}) echo 'F12';;
$'\e'${fnkey[13]}) echo 'F13';;
$'\e'${fnkey[14]}) echo 'F14';;
$'\e'${fnkey[15]}) echo 'F15';;
$'\e'${fnkey[16]}) echo 'F16';;
$'\e'${fnkey[17]}) echo 'F17';;
$'\e'${fnkey[18]}) echo 'F18';;
$'\e'${fnkey[19]}) echo 'F19';;
$'\e'${fnkey[20]}) echo 'F20';;
$'\e'${fnkey[21]}) echo 'F21';;
$'\e'${fnkey[22]}) echo 'F22';;
$'\e'${fnkey[23]}) echo 'F23';;
$'\e'${fnkey[24]}) echo 'F24';;
^D) exit ;; # note: this is a real <ctrl>-<d>
*) echo "Key pressed: ${key_press}";;
esac
done
For me, this produces:
<~> $ /tmp/so8897.sh
Key pressed: q
Key pressed: w
Key pressed: e
Key pressed: r
Key pressed: t
Key pressed: y
F1
F2
F3
F4
F5
F6
F7
F8
F9
F10
F12
F13
F14
F15
F16
F17
F18
F19
F20
F21
F22
F23
F24

How to compare the content of two files in EFI Shell

I want to compare the content of two files in EFI Shell.
I saved the content of pci 05 00 00 in lan-ref.txt
My script looks like this:
echo -off
fs0:
pci 05 00 00 -s 0 > lan.txt
if lan.txt == lan-ref.txt then
reset
else
echo "LAN not found"
endif
I know that the "if lan.txt == lan-ref.txt" is not going to work, I am looking for the correct line to achieve the desired functionality.
Like #prl suggests, combine the comp command and %lasterror%:
comp lan-text lan-ref.txt
if %lasterror% eq 0 then
reset
else
echo "LAN not found"
endif
%lasterror% is equivalent to %errorlevel% in .bat scripts or $? in bourne shells and derivatives.
comp lan-text lan-ref.txt
if %lasterror% ==0 then
reset
else
echo "LAN not found"
endif

How to use arbitrary "sg_raw " argument in golang?

I am trying to replicate sg_inq through sg_raw
This is the command used:
inq_cmd := exec.Command("sg_raw", "-r", "512", "/dev/sg0", "12 00 00 00 60 00")
stdoutStderr, err := read_cmd.CombinedOutput()
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", stdoutStderr)
Output after execution is
Inq COMMAND :
exit status 1
Invalid command byte '12 00 00 00 60 00'
Inquire COMMAND :
2020/05/28 19:42:48 exit status 1
exit status 1
Invalid command byte '12 00 00 00 60 00'
Usage: sg_raw [OPTION]* DEVICE CDB0 CDB1 ...
Options:
-b, --binary Dump data in binary form, even when writing to stdout
-h, --help Show this message and exit
-i, --infile=IFILE Read data to send from IFILE (default: stdin)
-k, --skip=LEN Skip the first LEN bytes when reading data to send
-n, --nosense Don't display sense information
-o, --outfile=OFILE Write binary data to OFILE (def: hexdump to stdout)
-r, --request=RLEN Request up to RLEN bytes of data (data-in)
-R, --readonly Open DEVICE read-only (default: read-write)
-s, --send=SLEN Send SLEN bytes of data (data-out)
-t, --timeout=SEC Timeout in seconds (default: 20)
-v, --verbose Increase verbosity
-V, --version Show version information and exit
Between 6 and 256 command bytes (two hex digits each) can be specified
and will be sent to DEVICE. Lengths RLEN and SLEN are decimal by
default. Bidirectional commands accepted.
Simple example: Perform INQUIRY on /dev/sg0:
sg_raw -r 1k /dev/sg0 12 00 00 00 60 00
What's wrong in the command? It would be a great help! Thanks in advance!

How to batch files in shell script?

I would like to build a shell script to automatically archive object files into a static library, and copy all the headers and .a file to desired directory.
However, as the number of obj files grows, the following mess gets worse:
8 CWD=$(pwd)
9
10 FILE1="SDL_Logger.o"
11 HEADER1="SDL_Logger.h"
12 FILE2="SDL_Initializer.o"
13 HEADER2="SDL_Logger.h"
14 ARC="libsdlhelper.a"
15
16 INCLUDE=~/include
17 LIB=~/lib
18
19 if [ ! -f $FILE1 ];
20 then
21 echo " error: file $FILE1 does not exist. Abort."
22 else
23 if [ ! -f $FILE2 ];
24 then
25 echo " error: file $FILE2 does not exist. Abort."
26 else
27 echo " building archive... "
28 ar rs $ARC $FILE1 $FILE2
29
31 # lib
32 cp $ARC $LIB
34
35 # include
36 cp $HEADER1 $INCLUDE
37 cp $HEADER2 $INCLUDE
39
41 fi
42 fi
So, if I were to group all files into ONE variable like:
FILE="obj1.o obj2.o ... "
How would I check the existence of each file, and copy them(headers)? I can only do this one by one, which will be soon unacceptable.
Here is what I came up with to help you.
The best way to do this is using an array for FILE
short example to implement what you are trying to do:
# !/bin/bash
#define an array of files to look for
FILES=("SDL_Logger.h" "SDL_Initializer.h" "libsdlhelpere.o")
#define your directories
INCLUDE=~/include
LIB=~/lib
#set the amount of entries in our array
SIZE=${#FILES[#]}
# use for loop read all FILES
for (( i=0; i<${SIZE}; i++ ));
do
echo "checking for file: "${FILES[$i]}
if [ ! -f ${FILES[$i]} ];
then
echo " error: file"${FILES[$i]}" does not exist. Abort."
else
echo " building archive... "
fi
done
Here we define FILES as our array
FILES=("SDL_Logger.h" "SDL_Initializer.h" "libsdlhelpere.a")
then we Find the size of files
SIZE=${#FILES[#]}
Then we go through each file and execute a command which is echo and then our if statement:
for (( i=0; i<${SIZE}; i++ ));
do
Here is how we call our item in the array...
${FILES[$i]}
so in what we are doing in plain english is:
echo FILES[1]....
IF FILES[1] doesn't exist then error....
else execute building archive...
echo FILES[2]....
IF FILES[2] doesn't exist then error...
etc...
This will repeat until the SIZE of FILES in met.
Using this method you can also just define the beginning part of the file name such as
"SDL_Initializer" and have your loop add in the .o .h. .a etc... Maybe another array FILETYPES ;)
hope this helped...
Sorry I didn't complete the code for you :)
Here is an answer to the question as asked:
#!/bin/bash
FILES="SDL_Logger.o SDL_Initializer.o"
HEADERS="${FILES//.o/.h}"
ARC="libsdlhelper.a"
INCLUDE=~/include
LIB=~/lib
for f in ${FILES}; do
if [ ! -f "${f}" ]; then
echo "error: file ${f} does not exist. Abort."
exit 1
fi
done
ar rs ${ARC} ${FILES}
cp ${ARC} ${LIB}
cp ${HEADERS} ${INCLUDE}
However, as the comments point out, the right tool for this job is make. For example GNU make. If you plan on developing software on a unix platform, investing time learning make is time well spent.

Resources