Can an MD5-hash begin with a zero? What about SHA-1?
Yes:
$ echo -n "363" | md5sum
00411460f7c92d2124a67ea0f4cb5f85 -
$ echo -n "351" | sha1sum
0026476a20bfbd08714155bb66f0b4feb2d25c1c
Found by running the following in bash:
for i in {1..1000} ; do echo $(echo -n $i | md5sum) $i ; done | sort | head
Try with the string : jk8ssl
echo md5('jk8ssl')
generate :
00000000 18e6137a c2caab16 074784a6
I didn't find better yet ^^
I found a MD5 hash that beginns with a zero byte!
2 character String
Unicode
#7358 #34823
$returnValue = md5('Ჾ蠇');
result:
00000000 5e0a51c8 313ffb43 8a3a2861
Of course. Or two zeros. Or more. In general, the probability of a "random" input hashing to a result with k leading zero nybbles is about 2-4k.
md5 of a = 0cc175b9c0f1b6a831c399e269772661
<?php echo md5( 'a' ); ?>
Sha1 of i = 042dc4512fa3d391c5170cf3aa61e6a638f84342
<?php echo sha1( 'i' ); ?>
why not :D
MD5 hash of "a" = 0cc175b9c0f1b6a831c399e269772661
SHA1 hash of "9" = 0ade7c2cf97f75d009975f4d720d1fa6c19f4897
In a cryptographic hash, any given bit should be equally likely to be a 0 or a 1 for random inputs.
This thread is pretty old now, but there are some very high & very low value hashes for SHA1 and MD5 here:
https://web.archive.org/web/20171201071711/http://www.crysys.hu/hashgame/allrecord.php
One of those has 7 bytes of leading zeros.
Related
I'm unable to find any for loop syntax that works with ksh for me. I'm wanting to create a program that esentially will add up numbers that are assigned to letters when a user inputs a word into the program. I want the for loop to read the first character, grab the number value of the letter, and then add the value to a variable that starts out equaled to 0. Then the next letter will get added to the variable's value and so on until there are no more letters and there will be a variable from the for loop that equals a value.
I understand I more than likely need an array that specifies what a letter's (a-z) value would be (1-26)...which I am finding difficult to figure that out as well. Or worst case I figure out the for loop and then make about 26 if statements saying something like if the letter equals c, add 3 to the variable.
So far I have this (which is pretty bare bones):
#!/bin/ksh
typeset -A my_array
my_array[a]=1
my_array[b]=2
my_array[c]=3
echo "Enter a word: \c"
read work
for (( i=0; i<${work}; i++ )); do
echo "${work:$i:1}"
done
Pretty sure this for loop is bash and not ksh. And the array returns an error of typeset: bad option(s) (I understand I haven't specified the array in the for loop).
I want the array letters (a, b, c, etc) to correspond to a value such as a = 1, b = 2, c = 3 and so on. For example the word is 'abc' and so it would add 1 + 2 + 3 and the final output will be 6.
You were missing the pound in ${#work}, which expands to 'length of ${work}'.
#!/bin/ksh
typeset -A my_array
my_array[a]=1
my_array[b]=2
my_array[c]=3
read 'work?enter a word: '
for (( i=0; i<${#work}; i++ )); do
c=${work:$i:1} w=${my_array[${work:$i:1}]}
echo "$c: $w"
done
ksh2020 supports read -p PROMPT syntax, which would make this script 100% compatible with bash. ksh93 does not. You could also use printf 'enter a word: ', which works in all three (ksh2020, ksh93, bash) and zsh.
Both ksh2020 and ksh93 understand read var?prompt which I used above.
First check the input work, you only want {a..z}.
charwork=$(tr -cd "[a-z]" <<< "$work")
Next you can fill 2 arrays with corresponding values
a=( {a..z} )
b=( {1..26} )
Using these arrays you can make a file with sed commands
for ((i=0;i<26;i++)); do echo "s/${a[i]}/${b[i]}+/g"; done > replaceletters.sed
# test it
echo "abcz" | sed -f replaceletters.sed
# result: 1+2+3+26+
Before you can pipe this into bc, use sed to remove the last + character.
Append s/+$/\n/ to replaceletters.sed and bc can calculate it.
Now you can use sed for replacing letters by digits and insert + signs.
Combining the steps, you have
a=( {a..z} )
b=( {1..26} )
tr -cd "[a-z]" <<< "$work" |
sed -f <(
for ((i=0;i<26;i++)); do
echo "s/${a[i]}/${b[i]}+/g"
done
echo 's/+$/\n/'
) | bc
In the loop you can use $i and avoid array b, but remember that the array start with 0, so a[5] corresponds with 6.
It is easy to declare and store a number in array but problem is that the user gives input 1234 and i wanted to store this numbers as $array[0]=1, $array[1]=2, $array[2]=3, $array[3]=4 but instead what actually happens is that $array[0]=1234, $array[1]=null, $array[2]=null, $array[3]=null. I don't know how to store each number separately
#!/bin/bash
declare -a key
read -p "Enter the encryption key: " numbers
key=($numbers)
echo ${key[0]}
echo ${key[1]}
echo ${key[2]}
echo ${key[3]}.
Actual output:
Enter the encryption key: 1234
1234
null
null
null
Desired output:
Enter the encryption key: 1234
1
2
3
4
Thank you, in advance :)
There is also a possibility to use
key=(`grep -o . <<< "$numbers"`)
And you can access different letters in $numbers without creating an array by using a substring notation ${string:initial_index:length_of_substring}:
echo ${numbers:0:1}
echo ${numbers:1:1}
echo ${numbers:2:1}
echo ${numbers:3:1}
Seeing how you're using read so you already assume that there are no spaces in the key, you can do this:
#!/bin/bash
declare str
read -p "Enter the encryption key: " str
# replace each character with that character + space
spaced=$(echo "$str" | sed 's/\(.\)/\1 /g')
# without quotes, array elements will be each of the space-separated strings
numbers=( $spaced )
printf "array element %s\n" "${numbers[#]}"
Output:
Enter the encryption key: hello123
array element h
array element e
array element l
array element l
array element o
array element 1
array element 2
array element 3
You can try.
declare -a key
read -p "Enter the encryption key: " numbers
while read -n1 input; do
key+=("$input")
done < <(printf '%s' "$numbers")
printf '%s\n' "${key[#]}"
I am trying to read a file line by line and find the average of the numbers in each line. I am getting the error: expr: non-numeric argument
I have narrowed the problem down to sum=expr $sum + $i, but I'm not sure why the code doesn't work.
while read -a rows
do
for i in "${rows[#]}"
do
sum=`expr $sum + $i`
total=`expr $total + 1`
done
average=`expr $sum / $total`
done < $fileName
The file looks like this (the numbers are separated by tabs):
1 1 1 1 1
9 3 4 5 5
6 7 8 9 7
3 6 8 9 1
3 4 2 1 4
6 4 4 7 7
With some minor corrections, your code runs well:
while read -a rows
do
total=0
sum=0
for i in "${rows[#]}"
do
sum=`expr $sum + $i`
total=`expr $total + 1`
done
average=`expr $sum / $total`
echo $average
done <filename
With the sample input file, the output produced is:
1
5
7
5
2
5
Note that the answers are what they are because expr only does integer arithmetic.
Using sed to preprocess for expr
The above code could be rewritten as:
$ while read row; do expr '(' $(sed 's/ */ + /g' <<<"$row") ')' / $(wc -w<<<$row); done < filename
1
5
7
5
2
5
Using bash's builtin arithmetic capability
expr is archaic. In modern bash:
while read -a rows
do
total=0
sum=0
for i in "${rows[#]}"
do
((sum += $i))
((total++))
done
echo $((sum/total))
done <filename
Using awk for floating point math
Because awk does floating point math, it can provide more accurate results:
$ awk '{s=0; for (i=1;i<=NF;i++)s+=$i; print s/NF;}' filename
1
5.2
7.4
5.4
2.8
5.6
Some variations on the same trick of using the IFS variable.
#!/bin/bash
while read line; do
set -- $line
echo $(( ( $(IFS=+; echo "$*") ) / $# ))
done < rows
echo
while read -a line; do
echo $(( ( $(IFS=+; echo "${line[*]}") ) / ${#line[*]} ))
done < rows
echo
saved_ifs="$IFS"
while read -a line; do
IFS=+
echo $(( ( ${line[*]} ) / ${#line[*]} ))
IFS="$saved_ifs"
done < rows
Others have already pointed out that expr is integer-only, and recommended writing your script in awk instead of shell.
Your system may have a number of tools on it that support arbitrary-precision math, or floats. Two common calculators in shell are bc which follows standard "order of operations", and dc which uses "reverse polish notation".
Either one of these can easily be fed your data such that per-line averages can be produced. For example, using bc:
#!/bin/sh
while read line; do
set - ${line}
c=$#
string=""
for n in $*; do
string+="${string:++}$1"
shift
done
average=$(printf 'scale=4\n(%s) / %d\n' $string $c | bc)
printf "%s // avg=%s\n" "$line" "$average"
done
Of course, the only bc-specific part of this is the format for the notation and the bc itself in the third last line. The same basic thing using dc might look like like this:
#!/bin/sh
while read line; do
set - ${line}
c=$#
string="0"
for n in $*; do
string+=" $1 + "
shift
done
average=$(dc -e "4k $string $c / p")
printf "%s // %s\n" "$line" "$average"
done
Note that my shell supports appending to strings with +=. If yours does not, you can adjust this as you see fit.
In both of these examples, we're printing our output to four decimal places -- with scale=4 in bc, or 4k in dc. We are processing standard input, so if you named these scripts "calc", you might run them with command lines like:
$ ./calc < inputfile.txt
The set command at the beginning of the loop turns the $line variable into positional parameters, like $1, $2, etc. We then process each positional parameter in the for loop, appending everything to a string which will later get fed to the calculator.
Also, you can fake it.
That is, while bash doesn't support floating point numbers, it DOES support multiplication and string manipulation. The following uses NO external tools, yet appears to present decimal averages of your input.
#!/bin/bash
declare -i total
while read line; do
set - ${line}
c=$#
total=0
for n in $*; do
total+="$1"
shift
done
# Move the decimal point over prior to our division...
average=$(($total * 1000 / $c))
# Re-insert the decimal point via string manipulation
average="${average:0:$((${#average} - 3))}.${average:$((${#average} - 3))}"
printf "%s // %0.3f\n" "$line" "$average"
done
The important bits here are:
* declare which tells bash to add to $total with += rather than appending it as if it were a string,
* the two average= assignments, the first of which multiplies $total by 1000, and the second of which splits the result at the thousands column, and
* printf whose format enforces three decimal places of precision in its output.
Of course, input still needs to be integers.
YMMV. I'm not saying this is how you should solve this, just that it's an option. :)
This is a pretty old post, but came up at the top my Google search, so thought I'd share what I came up with:
while read line; do
# Convert each line to an array
ARR=( $line )
# Append each value in the array with a '+' and calculate the sum
# (this causes the last value to have a trailing '+', so it is added to '0')
ARR_SUM=$( echo "${ARR[#]/%/+} 0" | bc -l)
# Divide the sum by the total number of elements in the array
echo "$(( ${ARR_SUM} / ${#ARR[#]} ))"
done < "$filename"
I have a 2 dimensional array made up of letters in the first dimension and numbers in the second dimension. eg
a,1
b,3
c,9
d,8
What I would like to do is search to array for a character and return it's corresponding number. eg if $var='c' then the return value would be 9.
Being unfamiliar with Unix arrays, I was wondering if anyone knew how to do this simply?
Thanks :)
Here is what I came up with
arr1=(a b c d)
arr2=(1 3 9 8)
for ((index=0; index<${#arr1[#]}; index++)); do
if [ "${arr1[$index]}" = "$myCharacter" ]; then
echo $arr2[$index]
return
fi
done
echo 'Character not found'
Not sure if there was a shorter way to do this but works okay....
Assuming you have a file called array.txt with input like you show in the question,
$ var=c
$ awk -v key="$var" -F, '$1 ~ key {print $2; found=1} END { if (! found) { print "Key "key" not found";}}' array.txt
9
$ var=z
$ awk -v key="$var" -F, '$1 ~ key {print $2; found=1} END { if (! found) { print "Key "key" not found";}}' array.txt
Key z not found
You can use bash to prepare an associative array and lookup the value using the character:
declare -A ARR
ARR=( [a]=1 [b]=3 [c]=9 [d]=8 )
echo ${ARR[c]}
I'm interested in updating an array element value within a for loop, but my update definition is wrong, since the output contain [counter].
Here is the code I have:
declare -a mem_set=(0 0 0 0 0 0 0)
counter=0
for i in "${domain_path[#]}"
do
cd $i
echo "$(pwd)"
for mLine in $(grep 'default.default.minmaxmemory.main' start_params.properties)
do
echo "$mLine"
done
l_bound="Xmx"
r_bound="m"
mem_set[counter]=$(echo "$mLine" | sed -e "s/.*${l_bound}//;s/${r_bound}.*//")
echo "$mem_set[counter]"
let counter=counter+1
done
The loop and the $(echo "$mLine" | sed -e "s/.*${l_bound}//;s/${r_bound}.*//") run fine, but I can't manage to get the right output. What is my update statement is missing? The output of it is 2048[counter]. Also, instead of using another counter counter in addition to i, is it possible to use i for mem_set array as well (both arrays have the same size)?
Thank you
Since feature requests to mark a comment as an answer remain declined, I copy the above solution here.
can you change echo "$mem_set[counter]" to echo "${mem_set[counter]}" and see if that prints out the right value? – 1_CR
thank you for your suggestion. Changing the format worked, so now I get the right output. – Simply_Me
In bash, you would access a variable with $.
Try,
counter=`expr $counter + 1`
or
counter=$(( counter + 1 ))