I am working on raspberry pi, for the command :
char-write-req 0x0011 e00000e0
I am getting ouput1 as:
12 57 7e 35 2d 49
Similarly,
char-write-req 0x0011 e00100e1
output2 is:
23 45 76 3e 66 2d
In a similar way I am getting output for different commands, now I want to check for MSB and pass that bit in switch case i.e I want "1" from 12 of ouput1 and "2" from 23 of output2 and generate a switch case for that.
How can i do this?
Use cut -c 1 to get the first character from the output:
char-write-req 0x0011 e00000e0 | cut -c 1
For the case you use:
case `char-write-req 0x0011 e00000e0 | cut -c 1` in
1) echo "something" ;;
2) echo "something else" ;;
esac
Related
I have .php takes three parameters. For example: ./execute.php 11 111 111
I have like list of data in text file with spacing. For example:
22 222 222
33 333 333
44 444 444
I was thinking for using xargs to pass in the arguements but its not working.
here is my try
cat raw.txt | xargs -I % ./execute.php %0 %1 %2
doesn't work, any idea?
thanks for the help
As per the following transcript, you are not handling the data correctly:
pax> printf '2 22 222\n3 33 333\n4 44 444\n' | xargs -I % echo %0 %1 %2
2 22 2220 2 22 2221 2 22 2222
3 33 3330 3 33 3331 3 33 3332
4 44 4440 4 44 4441 4 44 4442
Each % is giving you the entire line, and the digit following the % is just tacked on to the end.
To investigate, lets first create a fake processing file proc.sh (and chmod 700 it so we can run it easily):
#!/usr/bin/env bash
echo "$# '$1' '$2' '$3'"
Even if you switch to xargs -I % ./proc.sh %, you'll find you get one argument with embedded spaces, not three individual arguments:
pax> vi proc.sh ; printf '2 22 222\n3 33 333\n4 44 444\n' | xargs -I % ./proc.sh %
1 '2 22 222' '' ''
1 '3 33 333' '' ''
1 '4 44 444' '' ''
The easiest solution is probably to switch to a for read loop, something like:
pax:~> printf '2 22 222\n3 33 333\n4 44 444\n' | while read p1 p2 p3 ; do ./proc.sh ${p1} ${p2} ${p3} ; done
3 '2' '22' '222'
3 '3' '33' '333'
3 '4' '44' '444'
You can see there the program is called with three arguments, you just have to adapt it to your own program:
while read p1 p2 p3 ; do ./proc.sh ${p1} ${p2} ${p3} ; done < raw.txt
I have a document whose lines are separated by "\t\n". Records are separated either by "\t", OR by "\n".
Normally, this should be a straigtforward awk query:
BEGIN {
RS='\t\n';
}
{
print;
print "Next entry:";
}
However, on a Mac, regular expressions do not seem to be supported (maybe I'm not doing something right?) So I tried, RS="\t\n"; however, this is interpreted as RS='\t | \n'. Similar problems running awk from the command line:
awk 1 RS='\t\n' ORS='abc' input > output
replaces the \t's, but leaves the \n's be.
Next try: using tr. This obviously fails for sequence of more than one character-- since \t and \n are both used individually in the rows.
Next:
sed -e '/\t\n/s//NextEntry:/g' input > output
However, doesn't work. Entering any ASCII character sequence instead of \t\n works.
Read the manual. It says that \t is not supported in sed strings. Fair enough
sed -e '/\x9\xa/s//abc/' input > output
Still doesn't work. Idea: use tr to replace \t and \n by characters unused in the input file, use sed to change them to what I want, and then tr to change the remaining characters back to what they should be.
tr: Illegal byte sequence
Turns out, that f6 character makes tr just totally fail.
Went through the suggestions in Sed not recognizing \t instead it is treating it as 't' why? . That might work for replacing output strings (except the "Pasting tab into command prompt via CTRL+V" suggestion-- the shell just rejected that paste.), but did not seem to help in my case.
Maybe it's because it's a Mac? Maybe it's because that's the text I'm looking for, not replacing with? Maybe it's the combination with \n?
Any other suggestions?
UPDATE:
I found thread How can I replace a newline (\n) using sed? . Apparently, I am unable even to replace a \n by the string "abc" using the suggestions in that thread.
EDIT: Hex head of source file:
5a 20 4e 4f 09 0a 41 53 20 4f 46 20 30 31 2d 30
34 2d 30 35 20 45 4d 50 4c 4f 59 45 45 0a 47 52
4f 55 50 09 48 49 52 45 20 44 41 54 45 09 53 41
4c 41 52 59 09 4a 4f 42 20 54 49 54 4c 45 09 0a
4a 4f 42 20 4c 45 56 45 4c 0a 53 45 52 49 45 53
09 41 50 50 54 20 54 59 50 45 09 0a 50 41 59 20
53 54 41 54 55 53 0a f6
Unfortunately, BSD awk, as also used on macOS, doesn't support multi-character record separators (RS) altogether (in line with POSIX) - only a single, literal character is supported.
BSD sed, as also used on macOS, supports only \n in regexes - any other escapes, including hex ones (e.g., \x09) are not supported.
See this answer of mine for a comprehensive comparison of GNU and BSD sed.
Assuming that your sed command works in principle, you can use an ANSI C-quoted string
($'\t') to splice a literal tab char. into your sed script (assumes bash (the macOS default shell), ksh, or zsh),:
sed -e ':a' -e '$!{N;ba' -e '}' -e '/'$'\t''\n/s//NextEntry:/g'
Note that, in order to replace newlines, you must instruct sed to read the entire file into memory first, which is what -e ':a' -e '$!{N;ba' -e '}' does (the BSD Sed-compatible form of the common GNU sed idiom :a;$!{N;ba}).
This question already has an answer here:
Sorting 3 columns and getting the average
(1 answer)
Closed 6 years ago.
I have a problem whenever I add more than 3 numbers with multiple operators. (I tried expr, bc,
SUM=$(( $S1 + $S2 + $S3 ))
and many other forms, but whenever I have 3 variables I get this error.
expr: non-integer argument
expr: syntax error
This is when I do it with 2 variables (works fine)
#!/bin/sh
FILE=$1
while read -r SID FIRST LAST S1 S2 S3
do
SUM=$(expr $S1 + $S2)
AVG=$(expr $SUM / 3)
printf '%d [%d] %s, %s\n' "$AVG" "$SID" "$LAST" "$FIRST"
done < "$FILE" | sort
and when I do 3 variables (doesn't work)
#!/bin/sh
FILE=$1
while read -r SID FIRST LAST S1 S2 S3
do
SUM=$(expr $S1 + $S2 + $S3)
AVG=$(expr $SUM / 3)
printf '%d [%d] %s, %s\n' "$AVG" "$SID" "$LAST" "$FIRST"
done < "$FILE" | sort
expr: non-integer argument
expr: syntax error
txt file
123456789 Lee Johnson 72 85 90
999999999 Jaime Smith 90 92 91
888111818 JC Forney 100 81 97
290010111 Terry Lee 100 99 100
199144454 Tracey Camp 77 84 84
299226663 Laney Camp 70 74 71
434401929 Skyler Camp 78 81 82
928441032 Jess Forester 85 80 82
928441032 Chris Forester 97 94 89
The shell absolutely supports this; thus, the problem is with your data. Try the following:
s1=1
s2=2
s3=3
echo $(( s1 + s2 + s3 ))
...run, and showing output 6, here.
Likewise:
s1=1
s2=2
s3=3
expr "$s1" + "$s2" + "$s3"
...run, and showing output 6, here.
I have a command that generates 3 lines of output such as
$ ./mycommand
1
asdf
qwer zxcv
I'd like to assign those 3 lines to 3 different variables ($a, $b, $c) such that
$ echo $a
1
$ echo $b
asdf
$ echo $c
qwer zxcv
I'm familiar with the while loop method that would normally be used for reading 3 lines at a time from output that contains sets of 3 lines. But that seems less than elegant considering my command will only ever output 3 lines.
I tried playing around with various combinations of values for IFS= and options for read -r a b c, sending the command output as stdin, but I could only ever get it to set the first line to the first variable. Some examples:
IFS= read -r a b c < <(./mycommand)
IFS=$'\n' read -r a b c < <(./mycommand)
IFS= read -r -d $'\n' < <(./mycommand)
If I modify my command so that the 3 lines are separated by spaces instead of newlines, I can successfully just use this variation as long as each former line is properly quoted:
read -r a b c < <(./mycommand)
And while that is working for the purposes of my current project, it's still bugging me that I couldn't get it to work the other way. So I'm wondering if anyone can see and explain what I was missing in my original attempt with the 3 lines of output.
If you want to read data from three lines, use three reads:
{ read -r a; read -r b; read -r c; } < <(./mycommand)
read reads a chunk of data and then splits it up. You couldn't get it to work because your chunks were always single lines.
Newer BASH versions support mapfile command. Using that you can read all the lines into an array:
mapfile -t ary < <(./command)
Check the array content:
declare -p ary
declare -a ary='([0]="1" [1]="asdf" [2]="qwer zxcv")'
Perhaps this explanation will be useful to you.
... it's still bugging me that I couldn't get it to work the other way. So I'm wondering if anyone can see and explain what I was missing in my original attempt with the 3 lines of output.
Simple: read works only with one line (by default). This:
#!/bin/bash
mycommand(){ echo -e "1\nasdf\nqwer zxcv"; }
read a b c < <(mycommand)
printf 'first : %s\nsecond : %s\nthird : %s\n' "$a" "$b" "$c"
Will print:
first : 1
second :
third :
However, using a null character will capture the whole string in (replace this line above):
read -d '' a b c < <(mycommand)
Will print:
first : 1
second : asdf
third : qwer zxcv
The read command absorbed the whole output of the command and was broken into parts with the default value of IFS: SpaceTabEnter.
In this specific example, that worked correctly because the last value is the one with more than one "part".
But this kind of processing is very brittle. For example: this other possible output of the command, the assignment to variables will break:
mycommand(){ echo -e "1 and 2\nasdf and dfgh\nqwer zxcv"; }
Will output (incorrectly):
first : 1
second : and
third : 2
asdf and dfgh
qwer zxcv
The processing is brittle. To make it robust we need to use a loop. But you say that that is something you already know:
#!/bin/bash
mycommand(){ echo -e "1 and 2\nasdf and dfgh\nqwer zxcv"; }
i=0; while read arr[i]; do ((i++)); done < <(mycommand)
printf 'first : %s\nsecond : %s\nthird : %s\n' "${arr[0]}" "${arr[1]}" "${arr[2]}"
Which will (correctly) print:
first : 1 and 2
second : asdf and dfgh
third : qwer zxcv
However, the loop could be made simpler using bash command readarray:
#!/bin/bash
mycommand(){ echo -e "1 and 2\nasdf and dfgh\nqwer zxcv"; }
readarray -t arr < <(mycommand)
printf 'first : %s\nsecond : %s\nthird : %s\n' "${arr[0]}" "${arr[1]}" "${arr[2]}"
And using a printf "loop" will make the structure work for any count of input lines:
#!/bin/bash
mycommand(){ echo -e "1 and 2\nasdf and dfgh\n*\nqwer zxcv"; }
readarray -t arr < <(mycommand)
printf 'value : %s\n' "${arr[#]}"
Hope that this helped.
EDIT
About nulls (in simple read):
In bash, the use of nulls is almost never practical. In specific, nulls are erased silently in most condidions. This solution does suffer of that limitation.
Including a null in the input:
mycommand(){ echo -e "1 and 2\nasdf and dfgh\n\000\n*\nqwer zxcv"; }
will make a simple read -r -d '' get the input up to the first null (understanding such null as the character with octal 000).
echo "test one:"; echo
echo "input"; echo
mycommand | od -tcx1
echo "output"; echo
read -r -d '' arr < <(mycommand)
echo "$arr" | od -tcx1
Gives this as output:
test one:
input
0000000 1 a n d 2 \n a s d f a n d
31 20 61 6e 64 20 32 0a 61 73 64 66 20 61 6e 64
0000020 d f g h \n \0 \n * \n q w e r z
20 64 66 67 68 0a 00 0a 2a 0a 71 77 65 72 20 7a
0000040 x c v \n
78 63 76 0a
0000044
output
0000000 1 a n d 2 \n a s d f a n d
31 20 61 6e 64 20 32 0a 61 73 64 66 20 61 6e 64
0000020 d f g h \n
20 64 66 67 68 0a
0000026
It is clear that the value captured by read stops at the first octal 000.
Which, frankly, is to be expected.
About nulls (in readarray):
I have to report, however, that readarray does not stop at the octal 000 but just silently removes it (an usual shell trait).
Running this code:
#!/bin/bash
mycommand(){ echo -e "1 and 2\nasdf and dfgh\n\000\n*\nqwer zxcv"; }
echo "test two:"; echo
echo "input"; echo
mycommand | od -tcx1
echo "output"; echo
readarray -t arr < <(mycommand)
printf 'value : %s\n' "${arr[#]}"
echo
printf 'value : %s\n' "${arr[#]}"|od -tcx1
Renders this output:
test two:
input
0000000 1 a n d 2 \n a s d f a n d
31 20 61 6e 64 20 32 0a 61 73 64 66 20 61 6e 64
0000020 d f g h \n \0 \n * \n q w e r z
20 64 66 67 68 0a 00 0a 2a 0a 71 77 65 72 20 7a
0000040 x c v \n
78 63 76 0a
0000044
output
value : 1 and 2
value : asdf and dfgh
value :
value : *
value : qwer zxcv
0000000 v a l u e : 1 a n d 2 \n
76 61 6c 75 65 20 3a 20 31 20 61 6e 64 20 32 0a
0000020 v a l u e : a s d f a n d
76 61 6c 75 65 20 3a 20 61 73 64 66 20 61 6e 64
0000040 d f g h \n v a l u e : \n v
20 64 66 67 68 0a 76 61 6c 75 65 20 3a 20 0a 76
0000060 a l u e : * \n v a l u e :
61 6c 75 65 20 3a 20 2a 0a 76 61 6c 75 65 20 3a
0000100 q w e r z x c v \n
20 71 77 65 72 20 7a 78 63 76 0a
0000113
That is, the null 000 or just \0 gets silently removed.
I have hex code of a binary in text (string) format. How do I convert it to a binary file using linux commands like cat and echo ?
I know command following command with create a binary test.bin. But what if this hexcode is in another .txt file ? How do I "cat" the content of text file to "echo" and generate a binary file ?
# echo -e "\x00\x001" > test.bin
use xxd -r. it reverts a hexdump to its binary representation.
source and source
Edit: The -p parameter is also very useful. It accepts "plain" hexadecimal values, but ignores whitespace and line changes.
So, if you have a plain text dump like this:
echo "0000 4865 6c6c 6f20 776f 726c 6421 0000" > text_dump
You can convert it to binary with:
xxd -r -p text_dump > binary_dump
And then get useful output with something like:
xxd binary_dump
If you have long text or text in file you can also use the binmake tool that allows you to describe in text format some binary data and generate a binary file (or output to stdout). It allows to change the endianess and number formats and accepts comments.
Its default format is hexadecimal but not limited to this.
First get and compile binmake:
$ git clone https://github.com/dadadel/binmake
$ cd binmake
$ make
You can pipe it using stdin and stdout:
$ echo '32 decimal 32 61 %x20 %x61' | ./binmake | hexdump -C
00000000 32 20 3d 20 61 |2 = a|
00000005
Or use files. So create your text file file.txt:
# an exemple of file description of binary data to generate
# set endianess to big-endian
big-endian
# default number is hexadecimal
00112233
# man can explicit a number type: %b means binary number
%b0100110111100000
# change endianess to little-endian
little-endian
# if no explicit, use default
44556677
# bytes are not concerned by endianess
88 99 aa bb
# change default to decimal
decimal
# following number is now decimal
0123
# strings are delimited by " or '
"this is some raw string"
# explicit hexa number starts with %x
%xff
Generate your binary file file.bin:
$ ./binmake file.txt file.bin
$ hexdump file.bin -C
00000000 00 11 22 33 4d e0 77 66 55 44 88 99 aa bb 7b 74 |.."3M.wfUD....{t|
00000010 68 69 73 20 69 73 20 73 6f 6d 65 20 72 61 77 20 |his is some raw |
00000020 73 74 72 69 6e 67 ff |string.|
00000027
In addition of xxd, you should also look at the packages/commands od and hexdump. All are similar, however each provide slightly different options that will allow you to tailor the output to your desired needs. For example hexdump -C is the traditional hexdump with associated ASCII translation along side.