LinuxQuestions.org
Welcome to the most active Linux Forum on the web.
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 11-06-2013, 01:40 PM   #1
keif
Member
 
Registered: Apr 2013
Posts: 107

Rep: Reputation: Disabled
Bash: Exit loop without exiting script


Hello everyone,

I'm trying to start a script by pinging a host, and if the host is down I want to move on to the next host on the list:

Code:
#!/bin/bash
grep lf /etc/storelist | awk '{print $1}' > /tmp/lf-hosts

for STORE in `cat /tmp/lf-hosts`
do

echo ==========
echo $STORE

ping -c 1 $STORE > /dev/null 2>/dev/null
        pingRet=$?
                        if [ $pingRet -eq 0 ]; then
                                start=0
                        elif [ $pingRet -eq 1 ]; then
                                echo Host down
                                exit
fi
                if [ "$start" = '0' ]; then
                        ssh vision@$STORE "\
                ls -l vision.cnf; \
                grep EXT_CREDIT_UPC vision.cnf | wc -l; \
                cp vision.cnf vision.cnf-newCreditMaps"
fi
done
Right now it's set up to exit the entire script if the store is down. What I want to do if the host is down is move on to the next host on the list instead of exiting the entire script.

Any help is greatly appreciated. Thanks.
 
Old 11-06-2013, 01:44 PM   #2
rtmistler
Moderator
 
Registered: Mar 2011
Location: USA
Distribution: MINT Debian, Angstrom, SUSE, Ubuntu, Debian
Posts: 9,882
Blog Entries: 13

Rep: Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930
Use break in place of exit

But actually, you said you wanted to move to the next host. Well, instead of break, you'll want to use continue.

Last edited by rtmistler; 11-06-2013 at 01:46 PM.
 
1 members found this post helpful.
Old 11-06-2013, 01:46 PM   #3
Robhogg
Member
 
Registered: Sep 2004
Location: Old York, North Yorks.
Distribution: Debian 7 (mainly)
Posts: 653

Rep: Reputation: 97
I think the command you're looking for is break:

Code:
$ man bash
...
       break [n]
              Exit from within a for, while, until, or select loop.  If  n  is
              specified, break n levels.  n must be ≥ 1.  If n is greater than
              the number of enclosing loops, all enclosing loops  are  exited.
              The  return  value is 0 unless n is not greater than or equal to
              1.
 
1 members found this post helpful.
Old 11-06-2013, 01:49 PM   #4
rtmistler
Moderator
 
Registered: Mar 2011
Location: USA
Distribution: MINT Debian, Angstrom, SUSE, Ubuntu, Debian
Posts: 9,882
Blog Entries: 13

Rep: Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930
Quote:
Originally Posted by keif View Post
What I want to do if the host is down is move on to the next host on the list instead of exiting the entire script.
Use continue to go on to the next loop iteration.

Use break to exit the loop but stay in the script.

Your title I think is misleading, you do not wish to exit your loop, just continue to the next loop iteration, which is the next host in your list.

Last edited by rtmistler; 11-06-2013 at 01:57 PM.
 
1 members found this post helpful.
Old 11-06-2013, 02:38 PM   #5
Firerat
Senior Member
 
Registered: Oct 2008
Distribution: Debian sid
Posts: 2,683

Rep: Reputation: 783Reputation: 783Reputation: 783Reputation: 783Reputation: 783Reputation: 783Reputation: 783
untested

Code:
#!/bin/bash
while read STORE;do
    echo ==========
    echo $STORE

    ping -c 1 $STORE 2>&1> /dev/null \
         || (
              echo "Host:${STORE} down"
            ) \
         && (
              ssh vision@${STORE} \
                "ls -l vision.cnf;
                 grep EXT_CREDIT_UPC vision.cnf | wc -l;
                 cp vision.cnf vision.cnf-newCreditMaps"
            )
done < <( awk '/lf/{print $1}' /etc/storelist )
no need for break or continue since the list construct 'handles' it

Last edited by Firerat; 11-06-2013 at 04:49 PM. Reason: fix redirection ( see post 8 ) , correction is red
 
1 members found this post helpful.
Old 11-06-2013, 04:06 PM   #6
keif
Member
 
Registered: Apr 2013
Posts: 107

Original Poster
Rep: Reputation: Disabled
Quote:
Originally Posted by Firerat View Post
untested

Code:
#!/bin/bash
while read STORE;do
    echo ==========
    echo $STORE

    ping -c 1 $STORE 2&1> /dev/null \
         || (
              echo "Host:${STORE} down"
            ) \
         && (
              ssh vision@${STORE} \
                "ls -l vision.cnf;
                 grep EXT_CREDIT_UPC vision.cnf | wc -l;
                 cp vision.cnf vision.cnf-newCreditMaps"
            )
done < <( awk '/lf/{print $1}' /etc/storelist )
no need for break or continue since the list construct 'handles' it
Thanks for this. I've been trying to find a better way to loop than the one I've been using.

---------- Post added 11-06-13 at 05:07 PM ----------

Thanks everyone for your help. It looks like 'continue' is exactly what I was looking for.
 
Old 11-06-2013, 04:42 PM   #7
PTrenholme
Senior Member
 
Registered: Dec 2004
Location: Olympia, WA, USA
Distribution: Fedora, (K)Ubuntu
Posts: 4,187

Rep: Reputation: 354Reputation: 354Reputation: 354Reputation: 354
If you're interested in a different approach, hear's a gawk script that searches my /etc/fstab for any mount directives for cifs files with a nofail option that are not mounted. If any such files are found, it searches for them on a set of predefined address ranges and mounts them when they are found, and updates a file in /etc with the found locations to be used for initialization for the next time the program is run.

I've highlighted the section of the code that does the search for the cifs file shares.
Code:
#!/usr/bin/gawk -f
###############################################################################
#
# Mount any available, unmounted, "nofail" cifs shares listed in /etc/fstab
#
# Note: This code reads from /etc/fstab, and ignores any input files.
#
###############################################################################
#
# Define the needed console code color setting values.
BEGIN {
  _csi     =  "\x1b" "["
  _reset   = _csi "0m"
  _bold    = _csi "1m"
  _red     = _csi "31m"
  _green   = _csi "32m"
  _brown   = _csi "33m"
  _blue    = _csi "34m"
  _magenta = _csi "35m"
  _cyan    = _csi "36m"
  _white   = _csi "37m"
}
#
# Set the default address in the pool to be scanned.
BEGIN {
  if (!_pool)  _pool=   "192.168."      # Base address block
  if (!_in)    _in=     1               # Look in the _pool._in address block
  if (!_from) _from=    101             # Starting at _pool._in._from
  if (!_to)   _to=      110             # Ending with _pool._in._to
}
#
# Get the list of currently mounted files (Ignoring all non-device mounts.)
BEGIN {
  while (getline res < "/proc/self/mounts") {
    if (res ~ /^\//) {
      nf=split(res,part)
      if (nf > 1) mtab[gensub("\\\\040"," ","g",part[2])]++
    }
  }
  close("/proc/self/mounts")
}
#
# Read in the domain_map file if it exists
BEGIN {
  map[""]=""
  delete map
  while ((getline domain_map < "/etc/domain_map" )>0) {
    if ("^[[:space:]]*#" ~ domain_map) continue
    nf=split(domain_map,token,/[[:space:]]*=[[:space:]]*/)
    if (nf != 2) continue
    map[token[1]]=map[token[1]] (map[token[1]]?":":"") token[2]
  }
  close("/etc/domain_map")
}
#
# Make sure that /etc/fstab is in the input file list
BEGIN {
  failed=1
  for (i=0;i < ARGC; ++i) {
    if (ARGV[i] == "/etc/fstab") {
      failed=0
      break
    }
  }
  if (failed) {
    ARGV[ARGC++]="/etc/fstab"
  }
}
#
# Main loop: Parse /etc/fstab to find any unmounted "cifs nofail" shares, and attempt to mount them.
#
#Skip any comment line
/^[[:space:]]*\#/ {
  next
}
# Remove any comments from the input line before trying to parse it.
{
    sub(/[[:space:]]*#.*$/,"")
}
# Skip any blank line
((/^[[:space:]]*$/) || (length($0)==0)) {
  next
}
# Is this a valid fstab entry?
(NF != 6) {
      printf("  %sWarning: \"%s\" does not contain exactly 6 fields. Skipped.%s\n", _bold  _red, $0, _reset) > "/dev/stderr"
  next
}
# Does this line have a fs_type of "cifs" and a "nofail" somewhere in the option string?
(($3 == "cifs") && ($4 ~ "nofail")) {
  gsub("\\\\040"," ",$2)
  # Skip this one if it's already mounted
  if (!($2 in mtab)) {
    line[++lines]=$0
    res=""
  }
  next
}
# O.K., /etc/fstab has been parsed. Do the mounting.
END {
  count=length(line)
  if (count > 0) {
    printf("\n%sAttempting to mount %d device%s listed in /etc/fstab as \"cifs nofail\".%s\n",
           _bold  _blue,
           count,
           ((count>1)?"s":""),
           _reset)
  }
  else {
    exit(0)
  }
# Attempt to mount any unmounted "nofail cifs" file(s) using the /etc/fstab entry.
  for (i in line) {
    failed=Mount(line[i], mtab, "", map)
    if (!failed) {
      delete line[i]
      ++mounted
    }
    if (failed == 3) {
      delete line[i]
    }
  }
# Do we have anything to do?
  if (length(line) == 0) {
    print "  " _bold  _green "No " (mounted?"other ":"") "unmounted \"nofail cifs\" devices were referenced in /etc/fstab." _reset > "/dev/stderr"
  }
  else {

  # Process the lines that are left from /etc/fstab
  #
  # For each server in the specified range . . .
    for (i=_from; i<=_to; ++i) {
  # If the list is now empty, we're all done.
      if (length(line) == 0) break
  # Get the next URL to try
      url=sprintf("%s%d.%d", _pool, _in,i)
      print _bold _magenta "  Trying " url _reset
  # Try to mount any unmounted shares using this URL            }
      failed=""
      for (j in line) {
        failed=Mount(line[j], mtab, url)
        if (!failed) {
  # Remove this entry if it's successfully mounted.
          ++mounted
          delete line[j]
  # And try this URL on any remaining unmounted shares
          for (k in line) {
            failed=Mount(line[k], mtab, url)
            if  (!failed) {
              ++mounted
              delete line[k]
            }
          }
        }
      }
    }
  }

# Create a new domain_map file if any mount attempts were successful.
  if (mounted) {
    subash="sudo bash "
    print "echo '# Map of domain names to IP4 addresses' > '/etc/domain_map'" | subash
    for (i in map) {
      print "echo " i " = " map[i] " >> /etc/domain_map" | subash
    }
    close(subash)
  }
# List any unmounted shares
  if (length(line) > 0) {
    printf("  %sNo server could be located from which the following shares could be mounted.\n%s", _bold  _red, _reset)
    for (j in line) {
      split(line[j], part, /[[:space:]]+/)
      printf("    %s%s%s\n", _bold  _red, part[1], _reset)
    }
  }
}
#######################################################################################################################
#
# Attempt to mount a cifs share using a specific URL or the url specified in /etc/domain_map
#
# Note: If map is specified, this function will recusively call itself using the map values as URLs
#
#######################################################################################################################
# Return 0 if successful
#        1 if the mount point is already in use
#        2 if the URL is valid but the share name is not found on that URL
#        3 if called with an invalid fstab entry
#        the URL if the URL is not valid (So we can skip trying it again.)
function Mount(\
  line,                 # Line from /etc/fstab specifying a "cifs, noauto" mount\
  mtab,                 # Array of mounted files\
# Optional arguments
  url,                  # Url to try in place of the domain specified in /etc/fstab (if omitted, use the domain in fstab.)\
  Map,                  # Map of symbolic domain names to IP4 addresses (see /etc/domain_map)\
                        # Note: If Map is not an array and the mount is successful, the global map
                        # array will be updated with the URL.
# Local variables
  nf,i,j,k,             # Working values (count, indices, etc.)\
  part,                 # Whitespace delimited components of line.\
  domain,               # The domain specified in /etc/fstab\
  mapped,               # URLs to which a domain has been mapped\
  ret,                  # Mount command return status\
  error,                # Parsed error array\
  tmp)                  # Command return string(s) holder. (Note the -v option to the mount command.)
{
# Break the line from /etc/fstab into space delimited parts
  nf=split(line, part, /[[:space:]]+/)
  if (nf != 6) return 3
# Return without comment if this entry has already been mounted
  if (part[2] in mtab) return 1
# Split the first part (the device) into '/' delimited parts. Assume that the first part is the domain name
  split(part[1],domain,/\/+/)
# Do we have a replacement URL to use?
  if (url) {
    # Replace the domain with the URL
    sub(domain[2],url,part[1])
  }
# Make sure that the device string is terminated with a slash (to prevent share name collisions)
  if (part[1] !~ "/$") part[1] = part[1] "/"
# Change the "nofail" option (if any) to "noauto" so we will get an error if the mount fails
  gsub("nofail","noauto",part[4])
# Try to mount the share using the new URL (if any)
  cmd="sudo mount -v -t " part[3] " -o " part[4] " " part[1] " " part[2] " &>/dev/stdout"
# Check for any errors or URL failure
  ret=""
  while (cmd|getline tmp) {
    switch (tmp) {
      case /Unable to find suitable address/:
      case /could not resolve address/:
      case /No such device or address/:
      case /mount error/:
      case /mount.cifs error/:
      case /^[Ee]rror/:
        close(cmd)
        if (isarray(Map)) {
          split(part[1],domain,/\/+/)
          if (domain[2] in Map) {
            nf=split(Map[domain[2]], mapped, ":")
            for (i=1; i<=nf; ++i) {
              failed=Mount(line, mtab, mapped[i])
              if (!failed) {
                return 0
              }
            }
          }
        }
        return domain[2]
      case /\W[Ee]rror\W/:
        n=split(tmp, error, /[():][[:space:]]/)
        if (n >3) {
          ret=(ret?ret "\n" : "") "Error " error[2] ": " error[4]
        }
        else {
          ret=(ret?ret "\n" : "") tmp
        }
    }
  }
  close(cmd)
# Did we get an error return from the (attempted) mount?
  if (ret) {
    # Print the failure reason
    printf("  %sMount of %s from %s failed (%s).%s\n",_bold _red, part[2], part[1], ret, _reset)
    # And return 2 so other mounts for this share will be attempted on the other URLs
    return 2
  }
# O.K., we've got a successful mount.
  printf("  %sMounted %s from %s.%s\n", _bold  _green, part[2], (url ? url : domain[2]), _reset)
# Update the mtab array
  ++mtab[part[1]]
# Update the global array, map, if this was a direct mount
  if (!isarray(Map)) {
    if (domain[2] in map && map[domain[2]] !~ url) {
      map[domain[2]]=map[domain[2]] ":" url
    }
    else {
      map[domain[2]]=url
    }
  }
  return 0
}
 
Old 11-06-2013, 04:48 PM   #8
Firerat
Senior Member
 
Registered: Oct 2008
Distribution: Debian sid
Posts: 2,683

Rep: Reputation: 783Reputation: 783Reputation: 783Reputation: 783Reputation: 783Reputation: 783Reputation: 783
just noticed, there is an error in the redirection

it should be

Code:
2>&1 > /dev/null
sending stderr to stdout, and stdout to /dev/null
 
  


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
how to loop over text file lines within bash script for loop? johnpaulodonnell Linux - Newbie 9 07-28-2015 03:49 PM
script running ssh commands (via loop) exiting after first iteration kirecali Linux - Server 3 10-27-2010 05:41 AM
[SOLVED] [BASH] non-empty variable before loop end, is empty after exiting loop aitor Programming 2 08-26-2010 09:57 AM
Bash script problem with ftp session exiting the script early edomingox Programming 5 02-23-2010 05:39 AM
optional exit from loop, shell script RudraB Programming 2 07-17-2008 03:30 AM

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

All times are GMT -5. The time now is 08:53 AM.

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