Ping from within bash?

This is a general Linux question that I hope someone can help with. I have a portable drive that I use at both home & work, running a VM, and I want to be able to rsync my applications directory to backup servers at both locations. Both backup servers are on LAN's, one is a home LAN (192.168.1.2), the other uses a different address structure, and neither backup server is accessible from outside its own LAN.

I am running a bash script which issues the rsync command to both destinations, only one of which succeeds. I thought it might be possible to test which server is available via ping, and only issue the rsync command to the responding server.

Is it possible to do this in a bash script? If so how would I capture the successful ping output and use it to launch the command - in Perl I would use something like:

if ($successfulpingtoservera ) { rsyncservera() }

elsif ($successfulpingtoserverb ) { rsyncserverb() }

An alternative would be to test the VM's IP address which is different in both locations and would enable the script to determine the correct server to rsync with. But I've no idea how to do any of this in a shell script.

19 Replies

In bash, you can send a single ping:

ping -c1 192.168.100.67 2>&1 > /dev/null

and then test the result via the '$?' variable. It'll be 0 if successful, non-zero if not. Something like:

if [ $? == 0 ] ; then <successful ping="" action="">
elif <failed ping="" action=""></failed></successful>

HTH

Yes that works a treat. Many thanks.

Note that transient packet loss may cause the ping to fail - I'd have a loop to retry if both fail to respond.

OK, how's this:

for i in 1 2

ping -c1 $WORK 2>&1 > /dev/null

if [ $? == 0 ] ; then

rdiff-backup –remote-schema 'ssh -p 22 %s rdiff-backup --server' --exclude **/.svn $SOURCE $WORK::$DEST

echo 'rdiff-backup to WORK successful'

done

else ping -c1 $HOME 2>&1 > /dev/null

if [ $? == 0 ] ; then

rdiff-backup –remote-schema 'ssh -p 2995 %s rdiff-backup --server' --exclude **/.svn $SOURCE $HOME::$DEST

echo 'rdiff-backup to HOME successful'

done

fi

fi

echo 'rdiff-backup unsuccessful'

done

I have the nested statements indented but the formatting isn't reproduced here.

@jti:

OK, how's this:

for i in 1 2
  ping -c1 $WORK 2>&1 > /dev/null

  if [ $? == 0 ] ; then 
      rdiff-backup --remote-schema 'ssh -p 22 %s rdiff-backup --server' --exclude **/.svn $SOURCE $WORK::$DEST
    echo 'rdiff-backup to WORK successful'
    done
else ping -c1 $HOME 2>&1 > /dev/null
    if [ $? == 0 ] ; then 
        rdiff-backup --remote-schema 'ssh -p 2995 %s rdiff-backup --server' --exclude **/.svn $SOURCE $HOME::$DEST
        echo 'rdiff-backup to HOME successful'
        done
    fi
fi
echo 'rdiff-backup unsuccessful'
done

I have the nested statements indented but the formatting isn't reproduced here.
To escape a shell loop early, you must use break, not done.

Also, use code tags to indent properly :)

> To escape a shell loop early, you must use break, not done.

Yes, I realised that sometime after I posted and found it didn't actually work, and went back to Google for some answers! Also needed to use 'do ping' after the 'for i in 1 2' statement. It seems to be working properly now.

While there are some nice characteristics about bash (or shell scripting in general), at a certain level of complexity, switching to perl or python makes life much easier. Yes, interacting with the filesystem or other processes becomes a little more verbose (less so in perl), but you gain a level of consistency and power (again, less so in perl (yeah, I'm a python fan)) that will make your life happier and less error-prone in the long run.

Yes I normally do things like that in Perl (never used Python), but thought it was time I learned some shell scripting. Not sure about Python being more powerful than Perl though :)

Well, at the risk of igniting a programming flame war and going seriously OT - I tried Ruby and soon wondered what it can do that Perl can't. It's probably a reasonble choice though for someone starting out with no 'traditional' programming skills.

I also tried Rails, and again kept having the feeling that I can do all this stuff already in Perl, and that surely Perl must have an equivalent framework to Rails - and found Catalyst and have never looked back. YMMV of course :wink:

@jti:

Not sure about Python being more powerful than Perl though :)

Well, I was partially being facetious, and partially serious. I don't think Python is "more powerful" than Perl; they're roughly equivalent levels in the programming language hierarchy (the one that begins with assembler, then C, and ends with LISP). However, having done some work with both (I'm not an expert in either), I find Python to be a lot more readable and maintainable long-term, and have reduced my Perl usage to things that are basically fancy grep/sed/awk scripts, where matching a regexp is the main functionality (which Python can do too, of course, in a more wordy way), and which I really don't expect to have to re-use. I also am of the opinion that Python's OO facilities are a LOT more usable/readable/comfortable than Perl's blackmagic implementation. YMMV.

Ruby, at a very casual glance, appears to be more-or-less equivalent to Python, with a slightly more Perl-ish flavor. Which to prefer seems to be completely a matter of taste. I came across Python first, and don't feel a particular need to learn Ruby too.

@jti:

Well, at the risk of igniting a programming flame war i don't think there's any real risk of that here, lol. Like steve said though, it's not about which language is more powerful, they all three do the same things. Its about which is most elegant.

Hmm, consider the task of splitting a string into words and printing each on its own line. in ruby i would do:

"This is a string".split(" ").each {|w| printline w}

in perl i would do something like

$s = "This is a string";
while ($s =~ s/^(\w+ ?)//) {printline $1;}

Python would be similar to #1 yes? I would provide a python example but i'm sure it would suck.

Hmm, never heard of printline in Perl, and that's a truely horrible substitution for the Perl example :(

a nicer (IMO) version of the Perl example:

my $s = "This is a string";
print join ' ', split /\s+/, $s;

or:

my @words = split /\s+/, "This is a string";
print join ' ', @words; 

or if you want to do it on one line like the Ruby example:

print join ' ', split /\s+/, "This is a string";

or (almost) same thing:

print join ' ', split / /, "This is a string";

or same thing capturing the regex like the original example:

print join $1, split /(\s+)/, "This is a string";

or …. etc (TIMTOWTDI - in Perl ;))

Edit: sorry, just realised your example said to print each word on its own line (though your Perl example didn't do that!!). In that case replace all join ' ' in my examples with join "\n"

@jti:

Hmm, never heard of printline in Perl, and that's a truely horrible substitution for the Perl example :(
Thanks, those are much better examples than mine :).

as to the printline bit that i used, um, the implementation of printline is an exercise for the reader :wink:
> (though your Perl example didn't do that!!) that just depends on the implementation of printline, i guess.

There sure are many perl ways! heh

print join '\n', split / /, "This is a string";

this one stood out as my favorite. If you read it backwards its makes a lot of sense!

OK, printline could be a function/method, eg:

my $s = "This is a string";
while ($s =~ s/^(\w+ ?)//) {printline($1);}

sub printline {
  my $word = shift;
  print $word, "\n"; # or, less clear but all on one line: print $_[0], "\n";
}

In that case your example would indeed have done as you suggested, and printed one word per line. The bracket - printline() - just helps make it a bit clearer and less ambiguous, and means printline doesn't need to be pre-declared.

And of course I need to point out that
> print join '\n', split / /, "This is a string";
should read

print join "\n", split / /, "This is a string";

otherwise \n is interpreted literally - This\nis\na\nstring - which I'm sure was originally a typo and you knew that already :)

Of course, most of the time you're not dealing with a hard coded string but a variable, so

$var =~ tr/ /\n/;

@jti:

OK, printline could be a function/method, eg:

my $s = "This is a string";
while ($s =~ s/^(\w+ ?)//) {printline($1);}

sub printline {
  my $word = shift;
  print $word, "\n"; # or, less clear but all on one line: print $_[0], "\n";
}

In that case your example would indeed have done as you suggested, and printed one word per line. The bracket - printline() - just helps make it a bit clearer and less ambiguous, and means printline doesn't need to be pre-declared.

And of course I need to point out that
> print join '\n', split / /, "This is a string";
should read

print join "\n", split / /, "This is a string";

otherwise \n is interpreted literally - This\nis\na\nstring - which I'm sure was originally a typo and you knew that already :)

oh, what i was thinking for printline(str) was more something like: sub printline(str) {print str; print "\n";} and by "exercise for the reader" i just meant i was too lazy to type out the extra parts or think of a good way to put that newline character at the end of the string and so just fudged it.

EDIT oh nevermind thats the same as what you did, i just was having problems reading and thinking on that day i guess

@cz9qvh:

Python would be similar to #1 yes? I would provide a python example but i'm sure it would suck.

Just for the record the obvious way to do it in python (which is usually the best), is

s = "This is a string"
for w in s.split():
    print w

You can also do that last example in Perl too:

$s = "This is a string";
foreach $w (split(' ', $s)) {
    print "$w\n";
}

Or a bit less verbose:

$s = "This is a string";
for (split(' ', $s)) {
    print "$_\n";
}

Reply

Please enter an answer
Tips:

You can mention users to notify them: @username

You can use Markdown to format your question. For more examples see the Markdown Cheatsheet.

> I’m a blockquote.

I’m a blockquote.

[I'm a link] (https://www.google.com)

I'm a link

**I am bold** I am bold

*I am italicized* I am italicized

Community Code of Conduct