How do I use functions in bash?
I have a file with hashes of files against their filename. For example,
fb7e0a4408e46fd5573ffb9e73aec021a9dcf426235c0ccfc37d2f5e09a68a23 /path/to/some/file
237e0a4408e46fe3573f239e73aec021a9dcf426235c023fc37d2f5e09a68a12 /path/to/another/file
... and so on...
I need a hash converted to base64
encoded format.
So, I used a combination of bash function and awk
.
Here is what I wrote,
#!/bin/sh
base64Encode() {
$1 | openssl base64 -A
}
awk ' { t = base64Encode $1; print t } ' file.txt
But it doesn't work. I am using hashdeep
hash list to generate file and hashdeep
does not support base64
encoded output. This is why I am using openssl
.
Any help or advice regarding this would be great!
Edit:
The given answers work, but I am having another problem.
Usually cat filename | openssl dgst -sha256 | openssl base64 -A
gives base64
encoded output for a file filename
, which is completely absurd, and output from hashdeep
consistent output from cat filename | openssl dgst -sha256
. So, I thought about dumping the output I got from the previous step onto openssl base64 -A
for output base64
. But still I get different values ββfrom the actual result.
While it might be fine for an individual question, I would appreciate any support nonetheless.
source to share
Awk only:
$ awk '{ c="echo " $1 "|openssl base64 -A"
c | getline r
print r }' file
ZmI3ZTBhNDQwOGU0NmZkNTU3M2ZmYjllNzNhZWMwMjFhOWRjZjQyNjIzNWMwY2NmYzM3ZDJmNWUwOWE2OGEyMwo=
MjM3ZTBhNDQwOGU0NmZlMzU3M2YyMzllNzNhZWMwMjFhOWRjZjQyNjIzNWMwMjNmYzM3ZDJmNWUwOWE2OGExMgo=
For the rigid one-layer version, see @ 123's comment below.
... and @EdMorton is the super-fluid version (read: super-proof).
source to share
Since you are especially asking how to use functions, I have split the problem into several small functions. This is good practice in all (large) bash programs.
Rule of thumb: functions behave like any other command:
- you can redirect your I / O
- you can call them with arguments
- etc.
The best features are similar to regular unix executables, for example. reads from stdin and prints to stdout. This allows them to be used in pipelines as well.
So now rewrite:
# function for create base64 - reads from stdin, writes to stdout
base64Encode() {
openssl base64 -A
}
# function for dealing with your file
# e.g. reads lines "hash path" and prints "base64 path"
convert_hashes() {
while read -r hash path; do
b64=$(base64Encode <<< "$hash")
echo "$b64 $path"
done
}
#the "main" program
convert_hashes < your_file.txt
Output
ZmI3ZTBhNDQwOGU0NmZkNTU3M2ZmYjllNzNhZWMwMjFhOWRjZjQyNjIzNWMwY2NmYzM3ZDJmNWUwOWE2OGEyMwo= /path/to/some/file
MjM3ZTBhNDQwOGU0NmZlMzU3M2YyMzllNzNhZWMwMjFhOWRjZjQyNjIzNWMwMjNmYzM3ZDJmNWUwOWE2OGExMgo= /path/to/another/file
Yes, I know, I only want base64
without an attached path. From the course you can change the above convert_hashes
and remove the path from the exit, for example. instead echo "$b64 $path"
you can use echo "$b64"
and the output will only be a string b64
- but where you lose information in the function - which string belongs to which path - imho is not best practice.
Hence, you can leave the as-is function and use a different tool to get the first column - and only if needed - eg. in the "main" program. So you have developed a function for a later, more generic way.
convert_hashes < your_file.txt | cut -d ' ' -f1
Output
ZmI3ZTBhNDQwOGU0NmZkNTU3M2ZmYjllNzNhZWMwMjFhOWRjZjQyNjIzNWMwY2NmYzM3ZDJmNWUwOWE2OGEyMwo=
MjM3ZTBhNDQwOGU0NmZlMzU3M2YyMzllNzNhZWMwMjFhOWRjZjQyNjIzNWMwMjNmYzM3ZDJmNWUwOWE2OGExMgo=
Now, imagine you are expanding your script and want to not use files, but the input comes from another program: let's simulate this with the following function get_data
(of course, in a real application this will do something different, not just cat
:
get_data() {
cat <<EOF
fb7e0a4408e46fd5573ffb9e73aec021a9dcf426235c0ccfc37d2f5e09a68a23 /path/to/some/file
237e0a4408e46fe3573f239e73aec021a9dcf426235c023fc37d2f5e09a68a12 /path/to/another/file
EOF
}
now you can use all of the above like:
get_data | convert_hashes
the output will be the same as above.
of course you can do something about the way out, let him say
get_data | convert_hashes | grep another/file | cut -d ' ' -f1 MjM3ZTBhNDQwOGU0NmZlMzU3M2YyMzllNzNhZWMwMjFhOWRjZjQyNjIzNWMwMjNmYzM3ZDJmNWUwOWE2OGExMgo=
Of course, if you have such a "modular" structure, you can easily replace any parts, without having to touch other parts, for example, replacing openssl
with a command base64
.
base64Encode() { base64 }
And everything will go on without any changes. Of course, in a real application (perhaps) it is pointless to have a function that only calls one program, but I do this especially because you asked about functions.
Otherwise, the above can be made simple:
while read -r hash path; do
openssl base64 -A <<<"$hash"
echo
#or echo $(openssl base64 -A <<<"$hash")
#or printf "%s\n" $(openssl base64 -A <<<"$hash")
done < your_file.txt
or even
cut -d ' ' -f1 base | xargs -I% -n1 bash -c 'echo $(openssl base64 -A <<<"%")'
You need echo
or print
because it openssl
doesn't print newlines by default. Output:
ZmI3ZTBhNDQwOGU0NmZkNTU3M2ZmYjllNzNhZWMwMjFhOWRjZjQyNjIzNWMwY2NmYzM3ZDJmNWUwOWE2OGEyMwo=
MjM3ZTBhNDQwOGU0NmZlMzU3M2YyMzllNzNhZWMwMjFhOWRjZjQyNjIzNWMwMjNmYzM3ZDJmNWUwOWE2OGExMgo=
Ps: Honestly, I don't understand why you base64 encode some already encoded hash - but YMMV. :)
source to share