Passing arguments from a bash shell script to a command


 
Thread Tools Search this Thread
Top Forums Shell Programming and Scripting Passing arguments from a bash shell script to a command
# 1  
Old 02-24-2012
Passing arguments from a bash shell script to a command

I'm pretty new to bash scripting and I've found myself writing things like this (and the same with even more nesting):

Code:
    if $CATEGORIES; then
        if $LABEL_SLOTS; then
          $pyth "$wd/texify_grammar.py" "$input" "$texfile" "--label-slots" "--categories" "$CATEGORY_LIST"
        else
          $pyth "$wd/texify_grammar.py" "$input" "$texfile" "--categories" "$CATEGORY_LIST"
        fi
    else
        if $LABEL_SLOTS; then
          $pyth "$wd/texify_grammar.py" "$input" "$texfile" "--label-slots"
        else
          $pyth "$wd/texify_grammar.py" "$input" "$texfile"
        fi
    fi

There must be an easier way to do this... I've tried searching for the answer but haven't had much luck (probably because I don't know the right keywords to search for). Any help would be much appreciated!

Best wishes,
M
# 2  
Old 02-24-2012
Quote:
if $CATEGORIES; then
if $LABEL_SLOTS; then
In my Posix Shell (which is not bash) the above two conditions are always true regardless of whether the environment variables contain values or not.

Please post sample values of the variables and explain what decisions you need to make.
# 3  
Old 02-24-2012
That if-statement is wrong, I presume you're using -z or something to tell if they're blank...

Build a string:

Code:
# Replace $1, $2, ... with your options
set -- "$input" "$texfile"

# Append more options
[ ! -z "$LABEL_SLOTS" ] && set -- "$@" "--label-slots"
# Append more options
[ ! -z "$CATEGORIES" ] && set -- "$@" "--categories" "$CATEGORY_LIST"
...

# Test if it's really what you want
echo $pyth "$wd/texify_grammar.py" "$*"
# $pyth "$wd/texify_grammar.py" "$*"

If done carefully, this ought to even preserve spaces in arguments right, since the exact string "$@" expands to all the previous aruments exactly as given, warts and all.

Last edited by Corona688; 02-24-2012 at 11:53 AM..
# 4  
Old 02-24-2012
Thanks... that ought to be enough to let me figure it out. FWIW, the original code looked like this, and it works. (Which are certainly not to say that it couldn't be cleaner -- I'm only just starting with bash scripting.)


Code:
#!/usr/bin/bash                                                                                                        
 
wd=$(dirname "$0")
pyth=$(which python)
latex=$(which latex)
xelatex=$(which xelatex)
mkindex=$(which makeindex)

input="$wd/ALMSGrammar.txt"
texfile="$wd/build/ALMSGrammar.tex"

INDICES=false
LABEL_SLOTS=false
CATEGORIES=false

while getopts "isc:" opt; do
  case $opt in
    i)
      INDICES=true
      ;;
    s)
      LABEL_SLOTS=true
      ;;
    c)
      CATEGORIES=true
      CATEGORY_LIST=$OPTARG
      ;;
    \?)
      echo "Invalid option: -$OPTARG" >&2
      echo "Usage:" >&2
      echo -e "   -i \tgenerate indices" >&2
      echo -e "   -s \tlabel slots" >&2
      exit 1
      ;;
  esac
done

#there musst be an easier way of doing this...
if $INDICES; then
    if $CATEGORIES; then
        if $LABEL_SLOTS; then
          $pyth "$wd/texify_grammar.py" "$input" "$texfile" "--indices" "--label-slots" "--categories" "$CATEGORY_LIST"
        else
          $pyth "$wd/texify_grammar.py" "$input" "$texfile" "--indices" "--categories" "$CATEGORY_LIST"
        fi
    else
        if $LABEL_SLOTS; then
          $pyth "$wd/texify_grammar.py" "$input" "$texfile" "--indices" "--label-slots"
        else
          $pyth "$wd/texify_grammar.py" "$input" "$texfile" "--indices" 
        fi
    fi
else
    if $CATEGORIES; then
        if $LABEL_SLOTS; then
          $pyth "$wd/texify_grammar.py" "$input" "$texfile" "--label-slots" "--categories" "$CATEGORY_LIST"
        else
          $pyth "$wd/texify_grammar.py" "$input" "$texfile" "--categories" "$CATEGORY_LIST"
        fi
    else
        if $LABEL_SLOTS; then
          $pyth "$wd/texify_grammar.py" "$input" "$texfile" "--label-slots"
        else
          $pyth "$wd/texify_grammar.py" "$input" "$texfile"
        fi
    fi
fi

pushd "$wd/build"

if $INDICES; then
  "$latex" ALMSGrammar.tex
  "$mkindex" tokens
  "$mkindex" categories
  "$mkindex" todo
  "$latex" ALMSGrammar.tex
fi

"$xelatex" ALMSGrammar.tex
popd

mv "$wd/build/ALMSGrammar.pdf" "$wd"
open "$wd/ALMSGrammar.pdf"

# 5  
Old 02-24-2012
Quote:
Originally Posted by burbly
Thanks... that ought to be enough to let me figure it out. FWIW, the original code looked like this, and it works. (Which are certainly not to say that it couldn't be cleaner -- I'm only just starting with bash scripting.)
You've made two fundamental errors in such a way that they cancel each other out and work correctly here. I'm impressed Smilie

"true" and "false" are not special values to bash. They're just strings.

But...

As it happens, there are external utilities named true and false. true always returns success, and false always returns error.
Code:
$ whereis true
true: /bin/true /usr/share/man/man1/true.1.bz2 /usr/share/man/man1p/true.1p.bz2
$

Also, the code if program arguments ... is a way of checking the result of an external program. If $VARNAME was 'rm -Rf /home/myusername/', if $VARNAME would run the command rm -Rf /home/myusername/. If 'rm' succeeded in deleting your home directory, it would return a zero value, which the if-statement would consider a boolean 'true'. If it failed for some reason and returned a nonzero code, that would be a boolean 'false'.

So you've been converting the strings true and false into zero or nonzero program return codes, by running external programs that happen to be named true and false, then checking their result. Rather the long way around! Smilie

Seeing the code, if your filenames and arguments will never contain spaces, you can make this much much simpler:

Code:
#!/usr/bin/bash
 
wd=$(dirname "$0")
pyth=$(which python)
latex=$(which latex)
xelatex=$(which xelatex)
mkindex=$(which makeindex)

input="$wd/ALMSGrammar.txt"
texfile="$wd/build/ALMSGrammar.tex"

ARGS="$input $texfile"

while getopts "isc:" opt; do
  case $opt in
    i)
        ARGS="$ARGS --indices"
        INDICES=1
      ;;
    s)
      ARGS="$ARGS --label-slots"
      ;;
    c)
      ARGS="$ARGS --categories $OPTARG"
      ;;
    \?)
      echo "Invalid option: -$OPTARG" >&2
      echo "Usage:" >&2
      echo -e "   -i \tgenerate indices" >&2
      echo -e "   -s \tlabel slots" >&2
      exit 1
      ;;
  esac
done

# Note $ARGS is not in quotes and MUST NOT be in quotes.
# The spaces cause the arguments to split apart where you want them to.
# "$ARGS" would make it one giant argument.
$pyth "$wd/texify_grammar.py" $ARGS 

pushd "$wd/build"

# This is how you do string comparison!  -z means "if the string is empty".
# See http://tldp.org/LDP/abs/html/refcards.html#AEN22167 for details
# on more kinds of comparison.
if [ ! -z "$INDICES" ]
then
  "$latex" ALMSGrammar.tex
  "$mkindex" tokens
  "$mkindex" categories
  "$mkindex" todo
  "$latex" ALMSGrammar.tex
fi

"$xelatex" ALMSGrammar.tex
popd

mv "$wd/build/ALMSGrammar.pdf" "$wd"
open "$wd/ALMSGrammar.pdf"


Last edited by Corona688; 02-24-2012 at 01:15 PM..
This User Gave Thanks to Corona688 For This Post:
# 6  
Old 02-24-2012
Thanks! That's extremely helpful. I should be okay now.

FWIW, I didn't invent the true/false -- I got them out of an introduction to getopts that I found somewhere on the web. (And I hadn't had cause to use conditionals in a script before.)

Unfortunately I do have to deal with the possibility of spaces in filenames. (One of my collaborators works on a Mac, and this seems to be a perpetual issue there.) But I should still be able to adapt the

[ ! -z "$LABEL_SLOTS" ] && set -- "$@" "--label-slots"

to do the trick, right?

Edit: Actually, ack, it's just occurred to me that if I use set inside the getopts loop things are liable to go very wrong! I'll use three flags instead.
# 7  
Old 02-24-2012
Yes, set -- would mess up your arguments if you were still using the arguments at the time. Good thinking realizing that.

In the case of spaces in filenames, I'd use flags like you had, but use the set -- trick as well:

Code:
#!/usr/bin/bash                                                                                                        
 
wd=$(dirname "$0")
pyth=$(which python)
latex=$(which latex)
xelatex=$(which xelatex)
mkindex=$(which makeindex)

input="$wd/ALMSGrammar.txt"
texfile="$wd/build/ALMSGrammar.tex"

INDICES=
LABEL_SLOTS=
CATEGORY_LIST=

while getopts "isc:" opt; do
  case $opt in
    i)
      INDICES=1
      ;;
    s)
      LABEL_SLOTS=1
      ;;
    c)
      CATEGORY_LIST=$OPTARG
      ;;
    \?)
      echo "Invalid option: -$OPTARG" >&2
      echo "Usage:" >&2
      echo -e "   -i \tgenerate indices" >&2
      echo -e "   -s \tlabel slots" >&2
      exit 1
      ;;
  esac
done

set -- "$input" "$texfile"

[ -z "$INDICES" ] || set -- "$@" "--indices"
[ -z "$LABEL_SLOTS" ] || set -- "$@" "--label-slots"

[ -z "$CATEGORY_LIST" ] || set -- "$@" "--categories" "$CATEGORY_LIST"

$pyth "$wd/texify_grammar.py" "$@"

pushd "$wd/build"

if [ ! -z $INDICES ]
then
  "$latex" ALMSGrammar.tex
  "$mkindex" tokens
  "$mkindex" categories
  "$mkindex" todo
  "$latex" ALMSGrammar.tex
fi

"$xelatex" ALMSGrammar.tex
popd

mv "$wd/build/ALMSGrammar.pdf" "$wd"
open "$wd/ALMSGrammar.pdf"

You can also use arrays instead of "set --" to keep an argument list, but "set --" works in any bourne shell -- bash, ksh, old-fashioned sh, zsh, and more. This script would be simple to use anywhere. BASH arrays on the other hand only work when BASH is available...

---------- Post updated at 11:30 AM ---------- Previous update was at 11:26 AM ----------

As for what || and && do:

Code:
true && echo "&& checks if the previous command succeeded.  This should print."
false && echo "This shouldn't print because 'false' returns error"
true || echo "|| checks if the previous command failed.  This won't print."
false || echo "...but this will."

true && true && true && echo "You can chain on more than one."

true &&
        echo "You can break && statements across lines to avoid really wide scripts"

echo "Pipes also can be broken across lines like that" |
        cat

This User Gave Thanks to Corona688 For This Post:
Login or Register to Ask a Question

Previous Thread | Next Thread

10 More Discussions You Might Find Interesting

1. UNIX for Beginners Questions & Answers

Passing Arguments to shell script from file is not working as expected.

Hi All, I have below simple shell script in cloudera quick start vm cenos 6 which copy file from source to destination. # file_copy.sh source_dir = ${source_dir} target = ${target_dir} cp source_dir target and my parameter file is like below #parameter_file.txt source_dir =... (4 Replies)
Discussion started by: Narasimhasss
4 Replies

2. Shell Programming and Scripting

C shell script passing arguments problem.

I found something insteresting when I tested passing arguments into my scripts. My scripts is as below. % cat passarg.env #!/bin/csh echo "passarg: argv = $argv argv = $argv" passarg1.env $* % cat passarg1.env #!/bin/csh echo "passarg1: argv = $argv argvp=$argv" set str = "test... (5 Replies)
Discussion started by: bestard
5 Replies

3. Shell Programming and Scripting

Passing arguments to interactive program through bash script, here document

Dear Users, I have installed a standalone program to do multiple sequence alignment which takes user parameters to run the program. I have multiple sequence files and want to automate this process through a bash script. I have tried to write a small bash code but its throwing errors. Kindly... (13 Replies)
Discussion started by: biochemist
13 Replies

4. Shell Programming and Scripting

Passing arguments to a bash script

Hi, I wanted to pass an argument to a bash script. So that the argument is used inside the awk command inside the bash script. I know the noraml way of passing argument to a bash script as below : sh myScript.sh abc Inside the bash script i can use like this myArg1=$1 wc $myArg But... (8 Replies)
Discussion started by: shree11
8 Replies

5. Shell Programming and Scripting

Passing multiple arguments to a shell script

Hi Gurus, Need some help with the shell scripting here. #!/bin/ksh ps -ef | grep -i sample.ksh | grep -v grep > abc.txt if then echo "sample.ksh is executing" else echo "sample.ksh is not executing" fi (1 Reply)
Discussion started by: jayadanabalan
1 Replies

6. Programming

Passing arguments from java to script shell

Hello Please i want to pass parameter (the string s) to the shell script: Quote: String s="Hello"; Process process = Runtime.getRuntime().exec("sh script1.sh"); How can i do please? Thank you (0 Replies)
Discussion started by: chercheur857
0 Replies

7. Shell Programming and Scripting

passing arguments to unix command or script inside tclsh

hi everobody kindly consider the following in tclsh I understand that we can do the following %exec UnixCmd arg1 arg2 but if I assinged the arguments to a list insde tclsh how can I use them back i.e %set ArgList %exec UnixCmd %exec Unixcmd $list %exec all the... (1 Reply)
Discussion started by: Blue_shadow
1 Replies

8. Shell Programming and Scripting

Help required in passing multiple arguments from a shell script to a pl/sql block

Hi, hope everyone are fine. Please find my issue below, and I request your help in the same In a configuration file, i have a variable defined as below TEST = 'One','Two','Three' I am trying to pass this variable in to a sql script which is define in a pl/sql block as follows, In the... (1 Reply)
Discussion started by: ramakanth_burra
1 Replies

9. Shell Programming and Scripting

passing runtime arguments to a shell script...

hi I am new to shell programming.....my question is while running one of my shell program it stops in between to accept input from the user and proceeds furthur after giving input....I want to know whether I can set this input through some files so that the shell acript reads the input from the... (10 Replies)
Discussion started by: santy
10 Replies

10. Solaris

Passing arguments to a shell script from file while scheduling in cron

Hi, I have a shell script Scp_1.sh for which I have to pass 2 arguments to run. I have another script Scp_2.sh which in turns calls script Scp_1.sh inside. How do I make Scp_1.sh script to read arguments automatically from a file, while running Scp_2.sh? -- Weblogic Support (4 Replies)
Discussion started by: weblogicsupport
4 Replies
Login or Register to Ask a Question