I am using crypto++ library for some exercise. I am expecting the same output as from the sha256sum tool invoked from the shell.
// typedef unsigned char byte;
byte out[CryptoPP::SHA256::DIGESTSIZE];
byte in=65; // 'A'
CryptoPP::SHA256().CalculateDigest(out, &in, 1);
for(int i=0; i < CryptoPP::SHA256::DIGESTSIZE; i++)
std::cout << std::hex << (int)out[i];
std::cout << std::endl;
559aead08264d5795d399718cdd5abd49572e84fe55590eef31a88a08fdffd
$ echo A | sha256sum
06f961b802bc46ee168555f066d28f4f0e9afdf3f88174c1ee6f9de004fc30a0
Why are the two not equal?
echo appends a newline, so you're comparing the hashes of different strings. Use printf instead:
$ printf 'A' | sha256sum
559aead08264d5795d3909718cdd05abd49572e84fe55590eef31a88a08fdffd -
$ printf 'A\n' | sha256sum
06f961b802bc46ee168555f066d28f4f0e9afdf3f88174c1ee6f9de004fc30a0 -
In your command line, you're checksumming A + a line feed.
If your unix version supports it, use echo -n to echo without adding the line feed;
$ echo -n A | sha256sum
559aead08264d5795d3909718cdd05abd49572e84fe55590eef31a88a08fdffd -
Related
I have a script to generate char arrays from strings:
#!/bin/bash
while [ -n "$1" ]
do
echo -n "{" && echo -n "$1" | sed -r "s/((\\\\x[0-9a-fA-F]+)|(\\\\[0-7]{1,3})|(\\\\?.))/'\1',/g" && echo "0}"
shift
done
It works great as is:
$ wchar 'test\n' 'test\\n' 'test\123' 'test\1234' 'test\x12345'
{'t','e','s','t','\n',0}
{'t','e','s','t','\\','n',0}
{'t','e','s','t','\123',0}
{'t','e','s','t','\123','4',0}
{'t','e','s','t','\x12345',0}
But because sed considers each new line to be a brand new thing it doesn't handle actual newlines:
$ wchar 'test
> test'
{'t','e','s','t',
't','e','s','t',0}
How can I replace special characters (Tabs, newlines etc) with their escaped versions so that the output would be like so:
$ wchar 'test
> test'
{'t','e','s','t','\n','t','e','s','t',0}
Edit: Some ideas that almost work:
echo -n "{" && echo -n "$1" | sed -r ":a;N;;s/\\n/\\\\n/;$!ba;s/((\\\\x[0-9a-fA-F]+)|(\\\\[0-7]{1,3})|(\\\\?.))/'\1',/g" && echo "0}"
Produces:
$ wchar 'test\n\\n\1234\x1234abg
test
test'
{test\n\\n\1234\x1234abg\ntest\ntest0}
While removing the !:
echo -n "{" && echo -n "$1" | sed -r ":a;N;;s/\\n/\\\\n/;$ba;s/((\\\\x[0-9a-fA-F]+)|(\\\\[0-7]{1,3})|(\\\\?.))/'\1',/g" && echo "0}"
Produces:
$ wchar 'test\n\\n\1234\x1234abg
test
test'
{'t','e','s','t','\n','\\','n','\123','4','\x1234ab','g','\n','t','e','s','t',
test0}
This is close...
The first isn't performing the final replacement, and the second isn't correctly adding the last line
You can pre-filter before passing to sed. Perl will do:
$ set -- 'test1
> test2'
$ echo -n "$1" | perl -0777 -pe 's/\n/\\n/g'
test1\ntest2
This is a very convoluted solution, but might work for your needs. GNU awk 4.1
#!/usr/bin/awk -f
#include "join"
#include "ord"
BEGIN {
RS = "\\\\(n|x..)"
FS = ""
}
{
for (z=1; z<=NF; z++)
y[++x] = ord($z)<0x20 ? sprintf("\\x%02x",ord($z)) : $z
y[++x] = RT
}
END {
y[++x] = "\\0"
for (w in y)
y[w] = "'" y[w] "'"
printf "{%s}", join(y, 1, x, ",")
}
Result
$ cat file
a
b\nc\x0a
$ ./foo.awk file
{'a','\x0a','b','\n','c','\x0a','\0'}
I have a following content in the file:
NAME=ALARMCARDSLOT137 TYPE=2 CLASS=116 SYSPORT=2629 STATE=U ALARM=M APPL=" " CRMPLINK=CHASSIS131 DYNDATA="GL:1,15 ADMN:1 OPER:2 USAG:2 STBY:0 AVAL:0 PROC:0 UKNN:0 INH:0 ALM:20063;1406718801,"
I just want to filter out NAME , SYSPORT and ALM field using sed
Try the below sed command to filter out NAME,SYSPORT,ALM fields ,
$ sed 's/.*\(NAME=[^ ]*\).*\(SYSPORT=[^ ]*\).*\(ALM:[^;]*\).*/\1 \2 \3/g' file
NAME=ALARMCARDSLOT137 SYSPORT=2629 ALM:20063
why not using grep?
grep -oE 'NAME=\S*|SYSPORT=\S*|ALM:[^;]*'
test with your text:
kent$ echo 'NAME=ALARMCARDSLOT137 TYPE=2 CLASS=116 SYSPORT=2629 STATE=U ALARM=M APPL=" " CRMPLINK=CHASSIS131 DYNDATA="GL:1,15 ADMN:1 OPER:2 USAG:2 STBY:0 AVAL:0 PROC:0 UKNN:0 INH:0 ALM:20063;1406718801,"'|grep -oE 'NAME=\S*|SYSPORT=\S*|ALM:[^;]*'
NAME=ALARMCARDSLOT137
SYSPORT=2629
ALM:20063
Here is another awk
awk -F" |;" -v RS=" " '/NAME|SYSPORT|ALM/ {print $1}'
NAME=ALARMCARDSLOT137
SYSPORT=2629
ALM:20063
Whenever there are name=value pairs in input files, I find it best to first create an array mapping the names to the values and then operating on the array using the names of the fields you care about. For example:
$ cat tst.awk
function bldN2Varrs( i, fldarr, fldnr, subarr, subnr, tmp ) {
for (i=2;i<=NF;i+=2) { gsub(/ /,RS,$i) }
split($0,fldarr,/[[:blank:]]+/)
for (fldnr in fldarr) {
split(fldarr[fldnr],tmp,/=/)
gsub(RS," ",tmp[2])
gsub(/^"|"$/,"",tmp[2])
name2value[tmp[1]] = tmp[2]
split(tmp[2],subarr,/ /)
for (subnr in subarr) {
split(subarr[subnr],tmp,/:/)
subName2value[tmp[1]] = tmp[2]
}
}
}
function prt( fld, subfld ) {
if (subfld) print fld "/" subfld "=" subName2value[subfld]
else print fld "=" name2value[fld]
}
BEGIN { FS=OFS="\"" }
{
bldN2Varrs()
prt("NAME")
prt("SYSPORT")
prt("DYNDATA","ALM")
}
.
$ awk -f tst.awk file
NAME=ALARMCARDSLOT137
SYSPORT=2629
DYNDATA/ALM=20063;1406718801,
and if 20063;1406718801, isn't the desired value for the ALM field and you just want some subsection of that, simply tweak the array construction function to suit whatever your criteria is.
I have a C++ program in which I want to execute the following command:
cmd = "(diff <(perl -ne 's/^\\S+\\s//; if ((/aaa/ .. /bbb/) && /ccc/)"
" { print \"$_\"}' file1)"
"<(perl -ne 's/^\\S+\\s//; if ((/aaa/ .. /bbb/) && /ccc/)"
" { print \"$_\"} file2)) ";
I get this error when I want to execute this command:
Search pattern not terminated at -e line 1.
I've noticed that the following commands work like this:
cmd = "diff <(echo aa) <(echo bb)"
string strCall = "bash -c \"( " + cmd + " ) 2>&1\"";
stream = popen(strCall.c_str(),"r"); // doesn't work popen(**str**.c_str(),"r")
and an example perl command containing '"' works like this:
cmd = "perl -ne '{print \"$1\"}' file"
stream = popen(str.c_str(),"r"); // doesn't work popen(**strCall**.c_str(),"r");
but if the perl command doesn't contains '"', it works both ways:
cmd = "perl -ne '{print $1}' file"
string strCall = "bash -c \"( " + cmd + " ) 2>&1\"";
stream = popen(str.c_str(),"r"); // also works popen(**strCall**.c_str(),"r");
How can I do to use both diff and perl in the same command. I assume I have to use strCall.
I've tried also to escape the perl cmd like this, but it doesn't work:
cmd = "perl -ne '{print \\\"$1\\\"}' file" // one '/' for '/', one for "'" and one for '"'.
Also it didn't worked this, but I am however not allowed to use R("str"):
cmd = R"(perl -ne '{print \"$1\"}' file)"
string strCall = "bash -c \"( " + cmd + " ) 2>&1\"";
stream = popen(strCall.c_str(),"r")
Thanks.
I know I am not answering your question, but a common solution once you reach this many levels of quoting is to write a simple shell script and then call that from popen.
E.g., popen("/path/diffscript.sh", "r");
In my c++ program I want to execute a perl comand and read the output returned by the execution. I use popen for that, but I get an error when executing my command:
Command:
string cmd = "perl -ne 's/^\\S+\\s//; if ((/" +
pattern1+ " START/ .. /" + pattern2+ " END/) && /find/)"
" { print \"$_\"}' file";
stream = popen(cmd.c_str(),"r");
If I execute this command in the command line it works, but in C++ i get this error:
Search pattern not terminated at -e line 1.
The command that works in command line is, in C++ I already escaped the '\' and '"':
perl -ne 's/^\\S+\\s//; if ((/aaa START/ .. /bbb END/) && /find/) { print "$_"}' file
If I execute this command, it works: "perl -ne print $_ file".
But my initial command doesn't.
What I am doing wrong. Thanks.
It's your escape characters \. You'll have to double them up in the C++ string as \\ gets turned into \. Then the shell does it's processing as you see on the command line. i.e. another round of \\ turned into \.
You need to escape your backslashes (by adding more backslashes!).
std::string cmd = "perl -ne 's/^\\\\S+\\\\s//; if ((/" +
pattern1 + " START/ .. /" +
pattern2+ " END/) && /find/)"
" { print \"$_\"}' file";
In C++0x you can use raw R"(strings)" to avoid adding slashes. Compile with GCC like
g++ -std=c++0x -Wall popen.cpp
example:
std::string cmd_raw = R"(perl -ne 's/^\\S+\\s//; if ((/)" +
pattern1 + R"( START/ .. /)" +
pattern2 + R"( END/) && /find/))"
R"( { print \"$_\"}' file)";
This worked:
cmd = "perl -ne 's/^\\\\S+\\\\s//; if ((/" +
pattern1+ " START/ .. /" + pattern2+ " END/) && /find/)"
" { print \"$_\"}' file";
stream = popen(cmd.c_str(),"r");
I am using system(3) on Linux in c++ programs. Now I need to store the output of system(3) in an array or sequence. How I can store the output of system(3).
I am using following:
system("grep -A1 \"<weakObject>\" file_name | grep \"name\" |
grep -Po \"xoc.[^<]*\" | cut -d \".\" -f5 ");
which gives output:
changin
fdjgjkds
dglfvk
dxkfjl
I need to store this output to an array of strings or Sequence of string.
Thanks in advance
system spawns a new shell process that isn't connected to the parent through a pipe or something else.
You need to use the popen library function instead. Then read the output and push each string into your array as you encounter newline characters.
FILE *fp = popen("grep -A1 \"<weakObject>\" file_name | grep \"name\" |
grep -Po \"xoc.[^<]*\" | cut -d \".\" -f5 ", "r");
char buf[1024];
while (fgets(buf, 1024, fp)) {
/* do something with buf */
}
fclose(fp);
You should use popen to read the command output from stdin. so, you'd do something like:
FILE *pPipe;
pPipe = popen("grep -A1 \"\" file_name | grep \"name\" | grep -Po \"xoc.[^<]*\" | cut -d \".\" -f5 ", "rt")
to open it in read text mode and then use fgets or something similar to read from the pipe:
fgets(psBuffer, 128, pPipe)
The esier way:
std::stringstream result_stream;
std::streambuf *backup = std::cout.rdbuf( result_stream.rdbuf() );
int res = system("grep -A1 \"<weakObject>\" file_name | grep \"name\" |
grep -Po \"xoc.[^<]*\" | cut -d \".\" -f5 ");
std::cout.rdbuf(backup);
std::cout << result_stream.str();