Why does Perl and /bin/sha1 give different results? - perl

I'm confused as to why the following return separate sHA1s
$ perl -MDigest::SHA1 -E'say Digest::SHA1::sha1_hex("http://i.aultec.com/v/8066/Originals/1FTVX12585NA9832010.jpg");'
e1133fa3b7ea0bfb8ffa4d877932ed6c6fa10cef
$ echo "http://i.aultec.com/v/8066/Originals/1FTVX12585NA9832010.jpg" | sha1sum
5c3731e83ae0184ed93b595b9f5604863dd331e6 -
Which one is right? Am /I/ doing it wrong?
$ perl -MDigest::SHA -E'say Digest::SHA::sha1_hex("http://i.aultec.com/v/8066/Originals/1FTVX12585NA9832010.jpg");'
e1133fa3b7ea0bfb8ffa4d877932ed6c6fa10cef
You can see the digest is right in the successor (Digest::SHA)

Both are right. Your echo command includes a newline at the end. (and the perl string doesn't) Try with echo -n ...

Perl is giving you the hash of the literal string you entered, whereas echo is appending a newline. If you tell echo to not add a newline, you'll get the same result:
drewfus:~$ perl -MDigest::SHA1 -E'say Digest::SHA1::sha1_hex("foo");'
0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33
drewfus:~$ echo -n "foo" | sha1sum
0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33 -

This is such a frequent mistake and I've made it many times. The echo command is also returning a newline.

Related

Replace a string in file with new string containing $ sign in Perl

I am trying to replace string with a new string containing $(dollar) sign in a existing file.
I have used below (regex) line in my code but I am not able get the expected result. Please suggest the solution.
system("perl -pi -e \"s/length\\s+.*/length [index $pkt_len]/g if /^\\s*set_value\\s+length/\" $filename")
The way to find the solution is during debug you should print out the line of the system call and test it "by hand" if it works as expected in the shell.
My guess is that
system("perl -pi -e 's/length\\s+.*/length [index \\\$pkt_len]/g if /^\\s*set_value\\s+length/' $filename")
is a solution.
You need 7 backslashes (!):
system("echo a | perl -pe \"s/a/\\\\\\\$foo/\"");
Output:
$foo
First "echo a | perl -pe \"s/a/\\\\\\\$foo/\"" is interpreted by perl which reduces the string to echo a | perl -pe "s/a/\\\$foo/"
Then it is parsed by the shell sh to give : echo a | perl -pe s/a/\$foo/
Finally, it is parsed by perl a second time to give the output $foo.

Perl command for same behaviour as readlink?

What is the equivalent Perl command to the GNU coreutils command readlink -f?
If any component of the file name except the last one is missing or unavailable, readlink produces no
output and exits with a nonzero exit code. A trailing slash is
ignored.
You can use Cwd:
use Cwd 'abs_path';
my $path = "/some/arbitrary/path";
print abs_path($path);
Test:
for q in exists imaginary imarginary/imaginary ; do
echo "$q"
echo -n "readlink -f: " ; readlink -f "$q"
echo -n "abs_path: " ; perl -MCwd=abs_path -E'say abs_path $ARGV[0]' "$q"
echo
done
Output:
exists
readlink -f: /home/eric/exists
abs_path: /home/eric/exists
imaginary
readlink -f: /home/eric/imaginary
abs_path: /home/eric/imaginary
imaginary/imaginary
readlink -f: abs_path:
As a total Perl rookie, I'm happy to say I have figured out this STDIN solution all by myself (after several tries, remember that Perl's learning curve IS known to be steep).
devnull's solution was great with no doubt, but it was a little too "scriptish" for my taste - whereas I'd sometimes just want to pipe a perl one-liner to an echo'ed string, like this:
echo "/home/user/somesymlinkedpath" | perl -MCwd=abs_path -nle 'print abs_path $_'
So as there might be more people around who want to know about how to code this kind of piped form (making perl read the argument from STDIN), I've decided to post it here too.

redirecting multipiped output to a file handle in perl

I want to redirect this awk output to the file handle but no luck.
Code:
open INPUT,"awk -F: '{print $1}'/etc/passwd| xargs -n 1 passwd -s | grep user";
while (my $input=<INPUT>)
{
...rest of the code
}
Error:
Use of uninitialized value in concatenation (.) or string at ./test line 12.
readline() on closed filehandle INPUT at ./test line 13.
The error message shown is not directly related to the question in the subject.
In order to open a pipe and retrieve the result in Perl you have to add "|" at the very end of the open call.
The error message comes from the fact that Perl interprets the $1 you use in that double-quoted string. However, your intention was to pass that verbatim to awk. Therefore you have to escape the $ on the Perl side with \$.
There's a space missing in front of the /etc/passwd argument.
Summary: this should work better:
open INPUT,"awk -F: '{print \$1}' /etc/passwd| xargs -n 1 passwd -s | grep user|";
However, you should also check for errors etc.
It looks like $1 in the string you've passed is making Perl look for a variable $1 which you've not defined. Try escaping the $ in the string by putting a \ in front of it.
Because the string is not valid it doesn't do the open which then produces your second error.

how to trim wipe output with sed?

i want to trim an output of wipe command with sed.
i try to use this one:
wipe -vx7 /dev/sdb 2>&1 | sed -u 's/.*\ \([0-9]\+\).*/\1/g'
but it don't work for some reason.
when i use echo & sed to print the output of wipe command it works!
echo "/dev/sdb: 10%" | sed -u 's/.*\ \([0-9]\+\).*/\1/g'
what i'm doing wrong?
Thanks!
That looks like a progress indicator. They are often output directly to the tty instead of to stdout or stderr. You may be able to use the expect script called unbuffer (source) or some other method to create a pseudo tty. Be aware that there will probably be more junk such as \r, etc., that you may need to filter out.
Demonstration:
$ cat foo
#!/bin/sh
echo hello > /dev/tty
$ a=$(./foo)
hello
$ echo $a
$ a=$(unbuffer ./foo)
$ echo $a
hello

How do I push `sed` matches to the shell call in the replacement pattern?

I need to replace several URLs in a text file with some content dependent on the URL itself. Let's say for simplicity it's the first line of the document at the URL.
What I'm trying is this:
sed "s/^URL=\(.*\)/TITLE=$(curl -s \1 | head -n 1)/" file.txt
This doesn't work, since \1 is not set. However, the shell is getting called. Can I somehow push the sed match variables to that subprocess?
The accept answer is just plain wrong. Proof:
Make an executable script foo.sh:
#! /bin/bash
echo $* 1>&2
Now run it:
$ echo foo | sed -e "s/\\(foo\\)/$(./foo.sh \\1)/"
\1
$
The $(...) is expanded before sed is run.
So you are trying to call an external command from inside the replacement pattern of a sed substitution. I dont' think it can be done, the $... inside a pattern just allows you to use an already existent (constant) shell variable.
I'd go with Perl, see the /e option in the search-replace operator (s/.../.../e).
UPDATE: I was wrong, sed plays nicely with the shell, and it allows you do to that. But, then, the backlash in \1 should be escaped. Try instead:
sed "s/^URL=\(.*\)/TITLE=$(curl -s \\1 | head -n 1)/" file.txt
Try this:
sed "s/^URL=\(.*\)/\1/" file.txt | while read url; do sed "s#URL=\($url\)#TITLE=$(curl -s $url | head -n 1)#" file.txt; done
If there are duplicate URLs in the original file, then there will be n^2 of them in the output. The # as a delimiter depends on the URLs not including that character.
Late reply, but making sure people don't get thrown off by the answers here -- this can be done in gnu sed using the e command. The following, for example, decrements a number at the beginning of a line:
echo "444 foo" | sed "s/\([0-9]*\)\(.*\)/expr \1 - 1 | tr -d '\n'; echo \"\2\";/e"
will produce:
443 foo