LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   add options to bash script (https://www.linuxquestions.org/questions/programming-9/add-options-to-bash-script-4175422321/)

pablgonz 08-15-2012 11:22 PM

add options to bash script
 
Hello forum friends, I have the following bash script (which works perfectly), the code is as follows:
Code:

#!/bin/bash
# Compile big TeX proyect
# Set work dir
DIR="$( cd -P "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# Take name for proyect and create dir (mandato...)
echo Enter Name of proyect
read NAME
mkdir -p $DIR/backup/$NAME/{book,screen,legal,booklet}
echo "El Arbol de directorios para $NAME ha sido creado"
# First Option
# Compiling book (2 run)
for file in $DIR/source/book/*.tex
do pdflatex -interaction=batchmode -output-directory=$DIR/backup/$NAME/book/ "$file" >/dev/null 2>&1 &&
  pdflatex -interaction=batchmode -output-directory=$DIR/backup/$NAME/book/ "$file" >/dev/null 2>&1
done
echo "El Libro se ha creado con exito!"
# Second Option
# Compiling screen
for file in $DIR/source/screen/*.tex
do pdflatex -interaction=batchmode -output-directory=$DIR/backup/$NAME/screen/ "$file" >/dev/null 2>&1
done
echo "Las Presentaciones se han creado con exito!"
# Third Option
# Compilando legal
for file in $DIR/source/legal/*.tex
do pdflatex -interaction=batchmode -output-directory=$DIR/backup/$NAME/legal/ "$file" >/dev/null 2>&1
done
echo "El formato LEGAL se ha creado con exito!"
# Fourth Option
cp -R $DIR/source/facsimil/ /$DIR/backup/$NAME/
for file in $DIR/source/booklet/*.tex
do pdflatex -interaction=batchmode -output-directory=$DIR/backup/$NAME/facsimil "$file" >/dev/null 2>&1
done
cd $DIR/backup/$NAME/facsimil &&
for file in *.tex
do pdflatex -interaction=batchmode -output-directory=$DIR/backup/$NAME/booklet/ "$file" >/dev/null 2>&1
done
# Clean temp files and facsimil dir
rm -rf $DIR/backup/$NAME/facsimil/ &&
find $DIR/backup/$NAME/ -regextype posix-awk -regex "(.*.log|.*.toc|.*.xwm|.*.out|.*.aux)" -exec rm -rf {} \; &&
cd $DIR/backup/ &&
# Create back folder
tar -c --xz -f $NAME-$(date +%Y%m%d).tar.xz $NAME/
echo "El respaldo $NAME.tar.xz se ha creado con exito!"
# Move proyect
mv $DIR/backup/$NAME/ $DIR/store/
echo "The $NAME proyect its done"
exit 0

but, I would like to run it in parts, that is, add options to run.
My idea is to add the following
- book (create book)
- booklet (create booklet)
- screen (create screen)
- legal (make legal)
- all (all formats)
try to get married, but did not get what he wanted (I should clarify that I am not a programmer, and I believe it from google, this and other forums Linux users) if you help me with some example, or tell me I should improve on this script, would appreciate it.
regards
Pablo

David the H. 08-16-2012 08:22 AM

If I may, I'd like to first make a formatting suggestion.

It looks like a well-written script, much cleaner than many I've seen. But it's not very readable. You really need to use a lot more whitespace. Indent all your sub-commands evenly, and separate logical sections with empty lines. In other words, visually separate blocks of code that go together.


Next, please clarify your request a bit more. You want to add some features, ok. But what is the actual problem you're having in doing so?

If you want to know how to add command "flags" (e.g. something like "-b bookname" ), the usual technique is to use getopts.

http://wiki.bash-hackers.org/howto/getopts_tutorial




PS: More general advice:

QUOTE ALL OF YOUR VARIABLE SUBSTITUTIONS. You should never leave the quotes off a parameter expansion unless you explicitly want the resulting string to be word-split by the shell (globbing patterns are also expanded). This is a vitally important concept in scripting, so train yourself to do it correctly now. You can learn about the exceptions later.

http://mywiki.wooledge.org/Arguments
http://mywiki.wooledge.org/WordSplitting
http://mywiki.wooledge.org/Quotes

Also, since environment variables are generally all upper-case, it's good practice to keep your own user variables in lower-case or mixed-case to help differentiate them.

pablgonz 08-16-2012 11:59 AM

This its a second version (using case)
Code:

#!/bin/bash
# Compile big TeX proyect
# Set work dir
DIR="$( cd -P "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
echo Ingrese el nombre del proyecto
read NAME
echo 'Ingresa los parámetros'
read par
case $par in
        -b|book)
                mkdir -p $DIR/backup/$NAME/book &&
                echo "Creando libro para $NAME"
                for file in $DIR/source/book/*.tex
                do pdflatex -interaction=batchmode -output-directory=$DIR/backup/$NAME/book/ "$file" >/dev/null 2>&1 &&
                  pdflatex -interaction=batchmode -output-directory=$DIR/backup/$NAME/book/ "$file" >/dev/null 2>&1
                done
                echo "Done!"
                ;;
        -l|legal)
                mkdir -p $DIR/backup/$NAME/legal &&
                for file in $DIR/source/legal/*.tex
                do pdflatex -interaction=batchmode -output-directory=$DIR/backup/$NAME/legal/ "$file" >/dev/null 2>&1
                done
                echo "Done!"
                ;;
        -f|facsimil)
                mkdir -p $DIR/backup/$NAME/booklet
                cp -R $DIR/source/facsimil/ /$DIR/backup/$NAME/ &&
                for file in $DIR/source/booklet/*.tex
                do pdflatex -interaction=batchmode -output-directory=$DIR/backup/$NAME/facsimil "$file" >/dev/null 2>&1
                done &&
                cd $DIR/backup/$NAME/facsimil &&
                for file in *.tex
                do pdflatex -interaction=batchmode -output-directory=$DIR/backup/$NAME/booklet/ "$file" >/dev/null 2>&1
                done &&
                rm -rf $DIR/backup/$NAME/facsimil/
                ;;
        -s|screen)
                mkdir -p $DIR/backup/$NAME/screen &&
                for file in $DIR/source/screen/*.tex
                do pdflatex -interaction=batchmode -output-directory=$DIR/backup/$NAME/screen/ "$file" >/dev/null 2>&1
                done
                echo "Done!"
                ;;

        *)
                echo "The big TeX Proyect"
                echo "Usage: $0 {book|legal|facsimil|screen}"
                echo "        book    : Crea libro con marcas de agua."
                echo "        legal    : Crea las guías en formato legal."       
                echo "        screen  : Crea las presentaciones en pdf."
                echo "        facsimil : Crea los facsímiles en pdf."       
        ;;
esac
# Clean temp files
find $DIR/backup/$NAME/ -regextype posix-awk -regex "(.*.log|.*.toc|.*.xwm|.*.out|.*.aux)" -exec rm -rf {} \; &&
cd $DIR/backup/ &&
# Create backup folder
tar -c --xz -f $NAME-$(date +%Y%m%d).tar.xz $NAME/
echo "El respaldo del proyecto $NAME ha creado con exito!"
# Move proyect
mv $DIR/backup/$NAME/ $DIR/store/
echo "FINISH"
exit 0

but stay trapped to give more than one option to the script (-b -f -s -l and create the option - all).
Now I focus on the problem, I would like it to work well
Code:

sh script.sh name  -p -l -s -f
where "-p,-l,-s,-f" may be present or not. If the structure is not "case" allows me to do this, I can only run "one option" and not 2 or 3 same time, will review the link you give me and comment later.
grateful
Pablo

grail 08-16-2012 12:31 PM

Did you read David's post? He has suggested you look at getopts which will do exactly what you are looking for.

I would add that you have already given an interpreter inside the script, so to then run it with sh would seem pointless. Simply make it executable and run as you like.

David the H. 08-16-2012 12:44 PM

He did mention reviewing my link, grail.

In any case, we're on the right track; testing possible options with a case statement. The secret to the next step is to embed the whole thing inside a loop, allowing you to iterate over multiple inputs.

getopts simply provides a ready-built way to organize and parse such input options, particularly ones that can be followed by secondary arguments.

grail 08-16-2012 08:58 PM

My bad ... didn't read til the end of the line :(

pablgonz 08-16-2012 10:20 PM

Thanks for comment, check the links above and let me try to adapt to my needs, I stay with this option, it is quite clear to read (looks like perl structure), now the new script its :
Code:

#!/bin/bash
# Compile big TeX proyect
# Set work dir (good idea)
DIR="$( cd -P "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# Take proyect name from input
echo Ingrese el nombre del proyecto
read NAME
# Setting initial options
BOOK=1
LEGAL=0
SCREEN=0
FACSIMIL=0
# start script options
while [ $# -gt 0 ]; do
case $1 in
                -h|-help|--help)
                echo "The big TeX Proyect"
                echo "Usage: $0 -option1 -option2 --option3 --option4"
                echo "        -b|book    : Crea libro con marcas de agua."
                echo "        -l|legal    : Crea las guías en formato legal."       
                echo "        -s|screen  : Crea las presentaciones en pdf."
                echo "        -f|facsimil : Crea los facsímiles en pdf."
                echo "        -h|-help    : Muestra la ayuda y sale."               
                exit 0
                ;;
                -b|book)
                shift
                BOOK=1
                ;;
                -l|legal)
                shift
                LEGAL=1
                ;;
                    -f|facsimil)
                shift
                FACSIMIL=1
                ;;
                -s|screen)
                shift
                SCREEN=1
                ;;
                *)
                echo "Parametro no admitido: $1. Use \"$0 -h\" for help."
                exit 0
                ;;
                esac
        shift
done
# end options
# Compiling book
if [ $BOOK=0 ]; then
        mkdir -p $DIR/backup/$NAME/book &&
        echo "Creando libro para $NAME"
        for file in $DIR/source/book/*.tex
        do pdflatex -interaction=batchmode -output-directory=$DIR/backup/$NAME/book/ "$file" >/dev/null 2>&1 &&
        pdflatex -interaction=batchmode -output-directory=$DIR/backup/$NAME/book/ "$file" >/dev/null 2>&1
        done
        echo "BOOK Done!"
else
        echo "BOOK FAIL!"
fi
# Compiling legal
if [ "$LEGAL"=1 ]; then
        mkdir -p $DIR/backup/$NAME/legal &&
        for file in $DIR/source/legal/*.tex
        do pdflatex -interaction=batchmode -output-directory=$DIR/backup/$NAME/legal/ "$file" >/dev/null 2>&1
        done
        echo "LEGAL Done!"
else
        echo "LEGAL FAIL!"
fi
# Compiling screen
if [ "$FACSIMIL"=1 ]; then
        mkdir -p $DIR/backup/$NAME/booklet
        cp -R $DIR/source/facsimil/ /$DIR/backup/$NAME/ &&
        for file in $DIR/source/booklet/*.tex
        do pdflatex -interaction=batchmode -output-directory=$DIR/backup/$NAME/facsimil "$file" >/dev/null 2>&1
        done &&
        cd $DIR/backup/$NAME/facsimil &&
        for file in *.tex
        do pdflatex -interaction=batchmode -output-directory=$DIR/backup/$NAME/booklet/ "$file" >/dev/null 2>&1
        done &&
        rm -rf $DIR/backup/$NAME/facsimil/
        echo "FACSIMIL Done!"
else
        echo "FACSIMIL FAIL!"
fi
# Compiling screen
if [ "$SCREEN"=1 ]; then
        mkdir -p $DIR/backup/$NAME/screen &&
        for file in $DIR/source/screen/*.tex
        do pdflatex -interaction=batchmode -output-directory=$DIR/backup/$NAME/screen/ "$file" >/dev/null 2>&1
        done
        echo "SCREEN Done!"
else
        echo "SCREEN FAIL!"
fi
# end compiling files
# Clean temp files
find $DIR/backup/$NAME/ -regextype posix-awk -regex "(.*.log|.*.toc|.*.xwm|.*.out|.*.aux)" -exec rm -rf {} \; &&
cd $DIR/backup/ &&
# Create backup folder
tar -c --xz -f $NAME-$(date +%Y%m%d).tar.xz $NAME/
echo "El respaldo del proyecto $NAME ha creado con exito!"
# Move proyect
mv $DIR/backup/$NAME/ $DIR/store/
echo "FINISH"
exit 0

It does not work as they desire, the idea is to run for options, so as it is generated all at once,
What should I change? Or this is not the best way to achieve what I want? my idea is "sh script.sh -option1-option2..." enter, asks the name of the project and runs whit options.
regards
Pablo

grail 08-16-2012 11:33 PM

I am getting a little confused ... are you going to try the getopts suggestion?

pablgonz 08-17-2012 06:02 AM

Quote:

Originally Posted by grail (Post 4756325)
I am getting a little confused ... are you going to try the getopts suggestion?

Yes, I was trying more than one option but I think I found the solution (partial), this is the result of the script:
Code:

#!/bin/bash
# Compile big TeX proyect
# Set work dir (good idea)
# Using only case (not if ...then)
DIR="$( cd -P "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# Take proyect name from input
echo Ingrese el nombre del proyecto
read NAME
# start script options
while [ $# -gt 0 ]; do
case $1 in
                -h|-help|--help)
                echo "The big TeX Proyect"
                echo "Usage: $0 -b -l -f -s -h"
                echo "        -b|book    : Crea libro con marcas de agua."
                echo "        -l|legal    : Crea las guías en formato legal."       
                echo "        -s|screen  : Crea las presentaciones en pdf."
                echo "        -f|facsimil : Crea los facsímiles en pdf."
                echo "        -h|-help    : Muestra la ayuda y sale."               
                exit 0
                ;;
                -b|book)
                #shift
                BOOK=1
                mkdir -p $DIR/backup/$NAME/book &&
                echo "Creando book $NAME"
                for file in $DIR/source/book/*.tex
                do pdflatex -interaction=batchmode -output-directory=$DIR/backup/$NAME/book/ "$file" >/dev/null 2>&1 &&
                        pdflatex -interaction=batchmode -output-directory=$DIR/backup/$NAME/book/ "$file" >/dev/null 2>&1
                done
                echo "BOOK Done!"
                ;;
                -l|legal)
                #shift
                LEGAL=1
                mkdir -p $DIR/backup/$NAME/legal &&
                echo "Creando Legal $NAME"
                for file in $DIR/source/legal/*.tex
                do pdflatex -interaction=batchmode -output-directory=$DIR/backup/$NAME/legal/ "$file" >/dev/null 2>&1
                done
                echo "LEGAL Done!"
                ;;
                -f|facsimil)
                #shift
                FACSIMIL=1
                mkdir -p $DIR/backup/$NAME/booklet &&
                echo "Creando facsimil $NAME"
                  cp -R $DIR/source/facsimil/ /$DIR/backup/$NAME/ &&
                for file in $DIR/source/booklet/*.tex
                do pdflatex -interaction=batchmode -output-directory=$DIR/backup/$NAME/facsimil "$file" >/dev/null 2>&1
                done &&
                cd $DIR/backup/$NAME/facsimil &&
                for file in *.tex
                do pdflatex -interaction=batchmode -output-directory=$DIR/backup/$NAME/booklet/ "$file" >/dev/null 2>&1
                done &&
                rm -rf $DIR/backup/$NAME/facsimil/
                echo "FACSIMIL Done!"
                ;;
                -s|screen)
                #shift
                SCREEN=1
                mkdir -p $DIR/backup/$NAME/screen &&
                echo "Creando screen $NAME"
                for file in $DIR/source/screen/*.tex
                do pdflatex -interaction=batchmode -output-directory=$DIR/backup/$NAME/screen/ "$file" >/dev/null 2>&1
                done
                echo "SCREEN Done!"
                ;;
                *)
                echo "Parametro no admitido: $1. Use \"$0 -h\" for help."
                exit 0
                ;;
                esac
        shift
done
# end compiling files
# Clean temp files
find $DIR/backup/$NAME/ -regextype posix-awk -regex "(.*.log|.*.toc|.*.xwm|.*.out|.*.aux)" -exec rm -rf {} \; &&
cd $DIR/backup/ &&
# Create backup folder
tar -c --xz -f $NAME-$(date +%Y%m%d).tar.xz $NAME/
echo "El respaldo del proyecto $NAME ha creado con exito!"
# Move proyect
mv $DIR/backup/$NAME/ $DIR/store/
echo "FINISH"
exit 0

works almost as i want, but if the script call whit no options, this show me an error (and i would like to show me the help), which is not the correct use of "shift" (but that is responsible for moving the parameters entered). if you have any comments (format and eliminate code, correct use of shift) is appreciated.
Saludos
Pablo

grail 08-17-2012 11:14 AM

Well the simple solution to the no options problem would be to test for no options prior to running the script. This allows you to catch it but based on your current format would also
require you to duplicate the help section (perhaps a function would make this simpler)

You could reduce this to a single call to the help option if you also test for the -h and so on options are anywhere in $@, which is all options passed in

pablgonz 08-17-2012 02:10 PM

You're right, review the documentation on function to create the menu "help" and the test input, later commented the results

pablgonz 08-19-2012 05:11 PM

This is the forward end of the script, add the HELP function as, in one test to see if there was the directory with the name input, also has a test that shows if the help does not enter parameters. I only have two problems to solve:
1. Display "HELP" without having to enter NAME
2. Showing error when entering an option without "-", "--"
I think I could move up here with the links they gave me and the other post on the forum, but need help in this part of the most wise.
The Best
Pablo (Using fedora 17 and TeXLive2012)
The code:
Code:

#!/bin/bash
# Compile big TeX proyect 2012
# mycomp.sh
# Set work dir (good idea)
DIR="$( cd -P "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
# Help funtion
HELP(){
echo "The big TeX Proyect 2012"
                echo "Uso:sh $0 -b -l -f -s -h"
                echo "        -b|book    : Crea libro con marcas de agua."
                echo "        -l|legal    : Crea las guías en formato legal."       
                echo "        -s|screen  : Crea las presentaciones en pdf."
                echo "        -f|facsimil : Crea los facsímiles en pdf."
                echo "        -h|-help    : Muestra la ayuda y sale."               
}
# end help funtion
# If no argument given, show HELP and exit
if [ $# -lt 1 ] ;then
HELP
exit 0
fi
# Declaring getopt options
if ! options=$(getopt -o blsfh -l book,legal,facsimil,screen,help -- "$@");then
    # getopt will put out an error message
exit 0
fi
set --$options
# Take proyect name from input
echo Ingrese el nombre del proyecto
read NAME
if [ -d "$DIR/store/$NAME" ]; then
    echo "Ya existe $NAME intente con otro nombre"
    exit 0
fi
# start script options
while [ $# -gt 0 ]; do
# Case for param
case $1 in
                -h|--help)
                HELP
                exit 0 ;;
# Crea el libro desde source
            -b|--book)
                mkdir -p $DIR/backup/$NAME/book &&
                        echo "Creando book $NAME"
                for file in $DIR/source/book/*.tex
                        do pdflatex -output-directory=$DIR/backup/$NAME/book/ "$file" >/dev/null 2>&1 &&
                          pdflatex -output-directory=$DIR/backup/$NAME/book/ "$file" >/dev/null 2>&1
                done
                echo "BOOK Done!";;
# Crea las guias en formato 8.5x13 pulgadas
        -l|--legal)
                mkdir -p $DIR/backup/$NAME/legal &&
                echo "Creando Legal $NAME"
                for file in $DIR/source/legal/*.tex
                        do pdflatex -output-directory=$DIR/backup/$NAME/legal/ "$file" >/dev/null 2>&1
                done
                echo "LEGAL Done!";;
# Crea las guias tipo libro plegado 6.5x8.5 in
                -f|--facsimil)
                mkdir -p $DIR/backup/$NAME/booklet &&
                echo "Creando facsimil $NAME"
                  cp -R $DIR/source/facsimil/ /$DIR/backup/$NAME/ &&
                for file in $DIR/source/booklet/*.tex
                        do pdflatex -output-directory=$DIR/backup/$NAME/facsimil "$file" >/dev/null 2>&1
                done &&
                cd $DIR/backup/$NAME/facsimil &&
                for file in *.tex
                        do pdflatex -output-directory=$DIR/backup/$NAME/booklet/ "$file" >/dev/null 2>&1
                done &&
                cd $DIR/
                rm -rf $DIR/backup/$NAME/facsimil/
                echo "FACSIMIL Done!";;
# Crea las presentaciones usando pdfscreen
                -s|--screen)
                mkdir -p $DIR/backup/$NAME/screen &&
                echo "Creando screen $NAME"
        for file in $DIR/source/screen/*.tex
                        do pdflatex -output-directory=$DIR/backup/$NAME/screen/ "$file" >/dev/null 2>&1
                done
                echo "SCREEN Done!";;
# variousssss
            (--) shift; break;;
        (-*) echo "$0: error - $1" 1>&2; exit 1;;
        (*) break;;
        esac
shift
done
# Clean temp files
find $DIR/backup/$NAME/ -regextype posix-awk -regex "(.*.log|.*.toc|.*.xwm|.*.out|.*.aux)" -exec rm -rf {} \; &&
cd $DIR/backup/ &&
# Create backup folder
tar -c --xz -f $NAME-$(date +%Y%m%d).tar.xz $NAME/
echo "El respaldo del proyecto $NAME ha creado con exito!"
# Move proyect to store
mv $DIR/backup/$NAME/ $DIR/store/
echo "FINISH"
exit 0


grail 08-19-2012 08:43 PM

Quote:

1. Display "HELP" without having to enter NAME
Simply place your "-h|--help" in the same test as no options
Quote:

2. Showing error when entering an option without "-", "--"
You may need to consider the complexity here. This would mean that you never pass an argument (not a switch) that will not be the name of a switch.
I am not saying it is not correct but it does mean you are limiting the user in an unusual way.

It also appears that you are using getopts in an unusual way. Again not wrong but the the general idea would be to call getopts in your loop and do
the processing in one go.

You may like to look up here documents for your HELP function.

Also, the case calls seem to have a large amount of repetition with slight changes which would normally point to creating some functions.

pablgonz 08-19-2012 09:57 PM

Quote:

Originally Posted by grail (Post 4758616)
Simply place your "-h|--help" in the same test as no options

could give me an example of this (my attempts have not worked),as the "-h" is within "case" needs to go "NAME" first, which is not ideal.
Quote:

Originally Posted by grail (Post 4758616)
You may need to consider the complexity here. This would mean that you never pass an argument (not a switch) that will not be the name of a switch. I am not saying it is not correct but it does mean you are limiting the user in an unusual way.

It is built like this script, I have no experience in bash, perl is most common for me, but at this bash was the best option, the idea is to check error (and exit) if the parameter is not a valid option.
Quote:

Originally Posted by grail (Post 4758616)
It also appears that you are using getopts in an unusual way. Again not wrong but the the general idea would be to call getopts in your loop and do the processing in one go.

This is what I have in mind, the problem goes for $NAME, did not find how to include type "sh script.sh -b-f-l-s Name whit spaces and more ...", so I want to leave the function "HELP" before the "case" and verify that the parameters entered are valid, then income $NAME and run all.
Quote:

Originally Posted by grail (Post 4758616)
You may like to look up here documents for your HELP function. Also, the case calls seem to have a large amount of repetition with slight changes which would normally point to creating some functions.

I thought the truth, the functions are being as "sub run" but in this case it is better to leave it, for routing and call pdftex as I bring more of any inconvenience.
Grateful for your answer (and links)
Pablo

grail 08-19-2012 11:02 PM

As the script is to only accept switches and zero parameters, based on the following line of code:
Code:

echo "Uso:sh $0 -b -l -f -s -h"
The answer to:
Quote:

2. Showing error when entering an option without "-", "--"
Is that the bucket at the end of case will process these:
Code:

case blah in
1) do stuff;;
2) do other stuff;;
*) I do not know how to do this stuff
esac

I did notice to that under the --book option you have called pdflatex twice using the exact same information, is this a typo?


All times are GMT -5. The time now is 09:28 PM.