LinuxQuestions.org
Latest LQ Deal: Latest LQ Deals
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 01-05-2011, 06:40 PM   #1
Z038
Member
 
Registered: Jan 2006
Location: Dallas
Distribution: Slackware
Posts: 910

Rep: Reputation: 174Reputation: 174
bash md5sum edit with sed?


I am trying to get a checksum for a file in a subscripted variable in a bash script. md5sum outputs a checksum and the name of the input file. For example:

Code:
eval CSUM$K=\$"(md5sum file)"
This might return something like this:

Code:
3cff5d5c0113959d0be62be34b97e05c file
I want to assign just the checksum to the variable in my shell script and omit the file name that follows. Is there something besides md5sum that will generate a checksum? Or if not, then I was thinking I might be able to extract the checksum without the file name using sed.

Can someone show me how to do this?
 
Old 01-05-2011, 06:47 PM   #2
jschiwal
LQ Guru
 
Registered: Aug 2001
Location: Fargo, ND
Distribution: SuSE AMD64
Posts: 15,733

Rep: Reputation: 682Reputation: 682Reputation: 682Reputation: 682Reputation: 682Reputation: 682
Sed, Awk or cut could do it.

Code:
> md5cksum=($(md5sum Y* | cut -d' ' -f1))
> echo ${md5cksum[0]}
7f60a4e0b2a295f8e12a85cf2ef31c71
> echo ${md5cksum[1]}
8ad942f5605c6bf573cff17e84d23dcb
> echo ${md5cksum[2]}
a15672eab37e8a0d72bba89d117ac7d6
 
1 members found this post helpful.
Old 01-05-2011, 07:54 PM   #3
Z038
Member
 
Registered: Jan 2006
Location: Dallas
Distribution: Slackware
Posts: 910

Original Poster
Rep: Reputation: 174Reputation: 174
Thank you very much jschiwal. Your example using cut solved my problem.

I've only just started coding in bash, and it's very confusing to me. When I tried this in my do loop initially based on your suggestion:

Code:
CSUM$K=($(md5sum file | cut -d' ' -f1)
I get this

Code:
./test.sh: line 37: syntax error near unexpected token `$(md5sum file
./test.sh: line 37: `    CSUM$K=($(md5sum file | cut -d' ' -f1))'
but this worked

Code:
eval CSUM$K=\$"(md5sum file | cut -d' ' -f1)"
Why do I need to use eval?
 
Old 01-05-2011, 08:19 PM   #4
David1357
Senior Member
 
Registered: Aug 2007
Location: South Carolina, U.S.A.
Distribution: Ubuntu, Fedora Core, Red Hat, SUSE, Gentoo, DSL, coLinux, uClinux
Posts: 1,302
Blog Entries: 1

Rep: Reputation: 107Reputation: 107
Quote:
Originally Posted by Z038 View Post
Code:
CSUM$K=($(md5sum file | cut -d' ' -f1)
Remove the first "(" after the "=".
 
Old 01-05-2011, 08:42 PM   #5
jschiwal
LQ Guru
 
Registered: Aug 2001
Location: Fargo, ND
Distribution: SuSE AMD64
Posts: 15,733

Rep: Reputation: 682Reputation: 682Reputation: 682Reputation: 682Reputation: 682Reputation: 682
I don't follow what you want for "CSUM$K". In bash, it will first evaluate $K, add it to CSUM and try to execute the resulting string.
So,
K=A
CSUM$K

will try to run a program CSUMA.

The form
variable=(...)
Will initialize an array variable.
The form $( ... ) will execute the command inside the parenthesis and provide the output as arguments to a command.
It is the same as ` ... `

You access a bash array like:
${variable[index]}
the first element is 0.

You can count the number of elements.
$#{variable[@]}
Code:
md5sum *.pdf >pdf.md5
sums=($(cut -d' ' -f1 pdf.md5))
names=($(cut -d' ' -f3 pdf.md5 ))
echo ${sums[5]}
cbfff584cb597dcc152555736ac3f008
echo ${names[5]}
You could iterate through the elements in a loop like this:
Code:
for ((i=0,i<${#sums[*]};i++)); do
...
...
done
 
Old 01-06-2011, 04:04 AM   #6
bigearsbilly
Senior Member
 
Registered: Mar 2004
Location: england
Distribution: Mint, Armbian, NetBSD, Puppy, Raspbian
Posts: 3,515

Rep: Reputation: 239Reputation: 239Reputation: 239
alternatives without using cut

Code:
md5sum $1 |
while read sum file ; do
    echo sum = $sum
done

(
set $(md5sum $1)
    echo sum = $1
)

# if you use a decent shell (ksh) this would work:
md5sum $1 | read sum file
echo sum = $sum
Code:
$ bash 1.sh  demo959.tar.gz  
sum = 34190a633d15d7b9a3d2427a3d82b960
sum = 34190a633d15d7b9a3d2427a3d82b960
sum =

using korn shell much better
$ ksh 1.sh  demo959.tar.gz   
sum = 34190a633d15d7b9a3d2427a3d82b960
sum = 34190a633d15d7b9a3d2427a3d82b960
sum = 34190a633d15d7b9a3d2427a3d82b960
 
Old 01-06-2011, 04:15 AM   #7
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,007

Rep: Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191
Or just use substitution:
Code:
out=$(md5sum file)

echo ${out% *}
 
Old 01-06-2011, 08:02 AM   #8
crts
Senior Member
 
Registered: Jan 2010
Posts: 2,020

Rep: Reputation: 757Reputation: 757Reputation: 757Reputation: 757Reputation: 757Reputation: 757Reputation: 757
Quote:
Originally Posted by grail View Post
Or just use substitution:
Code:
out=$(md5sum file)

echo ${out% *}
Hi,

I would also opt for the substitution. However, there should be two '%' since one '%' will only match the shortest string from the end. Problematic if the filename contains spaces.
Code:
echo ${out%% *}
 
Old 01-06-2011, 08:37 AM   #9
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,007

Rep: Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191
@crts - fair call ... I tend to forget how people from the dark side love their space filled naming conventions
 
Old 01-06-2011, 11:54 PM   #10
Z038
Member
 
Registered: Jan 2006
Location: Dallas
Distribution: Slackware
Posts: 910

Original Poster
Rep: Reputation: 174Reputation: 174
Quote:
Originally Posted by jschiwal View Post
I don't follow what you want for "CSUM$K". In bash, it will first evaluate $K, add it to CSUM and try to execute the resulting string.
So,
K=A
CSUM$K

will try to run a program CSUMA.

The form
variable=(...)
Will initialize an array variable.
The form $( ... ) will execute the command inside the parenthesis and provide the output as arguments to a command.
It is the same as ` ... `

You access a bash array like:
${variable[index]}
the first element is 0.

You can count the number of elements.
$#{variable[@]}
Code:
md5sum *.pdf >pdf.md5
sums=($(cut -d' ' -f1 pdf.md5))
names=($(cut -d' ' -f3 pdf.md5 ))
echo ${sums[5]}
cbfff584cb597dcc152555736ac3f008
echo ${names[5]}
You could iterate through the elements in a loop like this:
Code:
for ((i=0,i<${#sums[*]};i++)); do
...
...
done
$K is the control variable in a do loop and it gets incremented by one on each iteration. I'm just trying to assign the md5sum of a file to a new variable each time through the loop. I don't want the variable to contain the file name, just the checksum. The cut command you demonstrated takes care of extracting the checksum without the file name.

The variable I am creating is of the form CSUM$K where $K goes from 1 to x. So I end up with variables like CSUM0 the first time through the loop, then CSUM1 the next time, then CSUM2, CSUM3, ... CSUMx. The value of each one of those variables is a different checksum.

I gather from what you are showing me that what I am doing is not the same as an array. Maybe an array would be easier, but the contents of the file I'm getting the checksum for changes each time through the loop.

I'm going to be trying your examples and some suggestions of others in this thread.
 
Old 01-07-2011, 01:46 AM   #11
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,007

Rep: Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191
Yes using your $K idea as the index to an array would make a lot more sense
Quote:
but the contents of the file I'm getting the checksum for changes each time through the loop.
You might need to explain this some more and maybe how you intend to use the checksums if the data keeps changing??
 
Old 01-07-2011, 09:43 PM   #12
Z038
Member
 
Registered: Jan 2006
Location: Dallas
Distribution: Slackware
Posts: 910

Original Poster
Rep: Reputation: 174Reputation: 174
I didn't express that well. I'm monitoring web site pages for changes. I wget several different web pages whose addresses are given by variables SITE0, SITE1, SITE2, etc, and save the initial checksum for each page in a variable like INIT0, INIT1, INIT2, etc. Then I go into a loop and issue another wget for each page, one page per loop iteration. Each time through the loop, I wget the corresponding SITE$K and save the md5sum checksum to CSUM$K, compare it with INIT$K, and send an email if checksum has changed and then assign the new CSUM$K to INIT$K. I then sleep for a while and then loop and check the next SITE$K.

Code:
#!/bin/bash
SITE0=http://www.website0.com/
SITE1=http://www.website1.com/
SITE2=http://www.website2.com/
SITE3=http://www.website3.com/
SITE4=http://www.website4.com/
K=0
while [ $K -lt 5 ]; do
   eval wget \$'SITE'$K --no-cookies -O initial
   eval INIT$K=\$"(md5sum initial | cut -d' ' -f1)"
   ((K++))
done
K=0
while [ $K -lt 5 ]; do
    eval wget \$'SITE'$K --no-cookies -O subsequent
    eval CSUM$K=\$"(md5sum subsequent | cut -d' ' -f1)"
    if [ "$(eval echo \$'INIT'$K)" != "$(eval echo \$'CSUM'$K)" ]; then
       eval echo -e change detected for \$'SITE'$K | mailx -s "SITE was updated" me@wherever.com
       eval INIT$K=CSUM$K
    fi
    sleep 10
    if [ $K == 4 ]; then 
       K=0
    else
       ((K++))
    fi
done
I'm going to try to rewrite this so I can read a list of sites from a file, set my loop counter to the number of records in the file, and then check each site on each iteration of the loop so that I can monitor an arbitrary number of sites on a regular interval. I will try to use arrays to hold the site names and checksums.

I know that monitoring web sites this way will result in a lot of emails, so this may not be an especially practical thing to do, but it is just an exercise to help me learn some techniques. It's a little more interesting than Hello World
 
Old 01-08-2011, 01:05 AM   #13
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,007

Rep: Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191
So untested of course seeing as sites are examples, but maybe something like this could work (I assumed it was to run forever, hence while true):
Code:
#!/bin/bash

SITES=( http://www.website0.com/
        http://www.website1.com/
        http://www.website2.com/
        http://www.website3.com/
        http://www.website4.com/ )

for SITE in ${SITES[*]}
do
    INIT+=( $(wget -O - $SITE --no-cookies | md5sum | cut -d' ' -f1) )
done

while true
do
    sleep 10

    for SITE in ${SITES[*]}
    do
        CSUM+=( $(wget -O - $SITE --no-cookies | md5sum | cut -d' ' -f1) )
    done

    for K in ${!SITES[*]}
    do
        if [[ ${INIT[K]} != ${CSUM[K]} ]]
        then
            echo -e change detected for ${SITE[K]} | mailx -s "SITE was updated" me@wherever.com
            ${INIT[K]}=${CSUM[K]}
        fi  
    done
done
 
1 members found this post helpful.
Old 01-08-2011, 01:54 AM   #14
Z038
Member
 
Registered: Jan 2006
Location: Dallas
Distribution: Slackware
Posts: 910

Original Poster
Rep: Reputation: 174Reputation: 174
That looks much neater than mine, and would not require making changes to hard coded loop values as sites are added. I like it. Thank you. Examples like this are very useful to me because I can relate what you did to my crude efforts in order to understand how it works.

Now if I can find a bash reference or guide that is easier to read and search than this one - http://www.gnu.org/software/bash/man...ef.html#Arrays - I'll be set.
 
Old 01-08-2011, 03:32 AM   #15
grail
LQ Guru
 
Registered: Sep 2009
Location: Perth
Distribution: Manjaro
Posts: 10,007

Rep: Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191Reputation: 3191
Well let us see if we can help with that too

I like / use the following:

http://tldp.org/LDP/abs/html/
http://mywiki.wooledge.org/TitleIndex (this one is a great reference for common mistakes that people (and even some sites) make)

This is another I have seen recommended:

http://www.gnu.org/software/bash/manual/bashref.html

One other piece of advice I would give to the code above as you mentioned the list of sites will probably grow is to place them all in a separate file and reference it in the script,
like so:
Plain file for sites: (I'll call it sites)
Code:
http://www.website0.com/
http://www.website1.com/
http://www.website2.com/
http://www.website3.com/
http://www.website4.com/
Change to original code above:
Code:
SITES=( http://www.website0.com/
        http://www.website1.com/
        http://www.website2.com/
        http://www.website3.com/
        http://www.website4.com/ )

# becomes

SITES=( $(< sites) )
Now you only ever need to edit the sites file and the code never needs to be touched
 
1 members found this post helpful.
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
[SOLVED] How do you use sed to edit a file? SparceMatrix Linux - General 3 09-04-2010 03:13 PM
using sed to edit html tkeyser Programming 6 08-20-2009 07:15 PM
SED: edit ip address n1wil Linux - Software 4 01-08-2008 02:18 PM
can sed edit individual characters/portions of a sentence? TGWDNGHN Linux - Software 10 10-18-2005 04:50 AM
Help with a script to edit text file (awk? sed?) rickh Linux - Newbie 8 04-21-2005 08:24 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 04:50 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration