tags:

views:

558

answers:

3

I am working on a bash script where I need to conditionally execute some things if a particular file exists. This is happening multiple times, so I abstracted the following function:

function conditional-do {
    if [ -f $1 ]
    then
        echo "Doing stuff"
        $2
    else
        echo "File doesn't exist!"
    end
}

Now, when I want to execute this, I do something like:

function exec-stuff {
    echo "do some command"
    echo "do another command"
}
conditional-do /path/to/file exec-stuff

The problem is, I am bothered that I am defining 2 things: the function of a group of commands to execute, and then invoking my first function.

I would like to pass this block of commands (often 2 or more) directly to "conditional-do" in a clean manner, but I have no idea how this is doable (or if it is even possible)... does anyone have any ideas?

Note, I need it to be a readable solution... otherwise I would rather stick with what I have.

A: 

One (possibly-hack) solution is to store the separate functions as separate scripts altogether.

Alex Gartrell
Sorry, the functions are all waaaaay too small for that, and I'm trying to merge it to 1 line so all needed to invoke is in the same place.
Mike Stone
+3  A: 

This should be readable to most C programmers:

function file_exists {
  if ( [ -e $1 ] ) then 
    echo "Doing stuff"
  else
    echo "File $1 doesn't exist" 
    false
  fi
}

file_exists filename && (
  echo "Do your stuff..."
)

or the one-liner

file_exists filename && echo "Do your stuff..."

Now, if you really want the code to be run from the function, this is how you can do that:

function file_exists {
  if ( [ -e $1 ] ) then 
    echo "Doing stuff"
    shift
    $*
  else
    echo "File $1 doesn't exist" 
    false
  fi
}

file_exists filename echo "Do your stuff..."

I don't like that solution though, because you will eventually end up doing escaping of the command string.

EDIT: Changed "eval $*" to $ *. Eval is not required, actually. As is common with bash scripts, it was written when I had had a couple of beers ;-)

Ludvig A Norin
That won't work, I have output to the user indicating whether or not it was done, which I want to keep... the point of the function was to get rid of all that boilerplate if, going back to inlining it would bloat the script again beyond what I want.
Mike Stone
The function I wrote is actually different a bit (I changed it above), but I do stuff in both the if and the else condition (which I abstracted out)... Also, the audience is not sysadmins/bash scripters... it's programmers who would be comfortable with functions.
Mike Stone
I think I understand what you need now. This is actually what many of my scripts look like. Updated it again :-)
Ludvig A Norin
Brilliant! Thanks!
Mike Stone
Added a "true" one-liner version that will evaluate the code from inside of the function. Ever heard of "bash-coma"? It's the condition that occurs after intense scripting sessions, when you start believing every problem could be solved with a good bash-script. Girlfriend grumpy? I can fix that. :-)
Ludvig A Norin
A: 

The cannonical answer:

[ -f $filename ] && echo "it has worked!"

or you can wrap it up if you really want to:

function file-exists {
    [ "$1" ] && [ -f $1 ]
}

file-exists $filename && echo "It has worked"
dsm