1

I know if I have a command ./run -c -p '$' -s 10 file.txt
I can write bash script like this

while read line; do 
   # ...
done < $6

But what if the command may or may not have one/some options, maybe look like this

./run -p '$' -s 10 file.txt

or this

./run '$' -s 10 file.txt

Then how can I get the file name in the script?

1
  • Note that your last snippet is nonstandard in that most (POSIX-compliant) utilities expect all option arguments before the non-option (filename) ones; in other words: most utilities would interpret all 3 arguments in your last snippet as non-option (filename) arguments.
    – mklement0
    Commented May 26, 2014 at 2:14

3 Answers 3

3

If the file name always comes at the end of the list of arguments, you can use "${@: -1}" to select the last argument. Taken from: https://stackoverflow.com/a/1854031/3565972

Eg.:

while read line; do 
   ...
done < "${@: -1}"
6
  • 2
    You need the space, otherwise the :- gets interpreted as "default value of 1".
    – Kevin
    Commented May 25, 2014 at 23:29
  • @Kevin Thanks for catching that!
    – savanto
    Commented May 25, 2014 at 23:31
  • May I know what if my filename is not at the end of the list of arguments? Than what should I refer to that filename? Thanks.
    – LuckyLast
    Commented May 26, 2014 at 5:56
  • @LuckyLast If you don't know the position of your filename, you can either pick it out of the arguments using something like a regex (eg. search for a string that looks like *.txt); you could use a flag to specify that a filename follows (eg. -f file.txt); or you could go with a robust method like getopts as suggested by user2303197
    – savanto
    Commented May 26, 2014 at 6:03
  • @savanto, Thank you for your response. but what if the command like this : ./run filename -c -p '$' -s 10, that getopts doesn't working on it.
    – LuckyLast
    Commented May 26, 2014 at 6:09
3

Use getopts to process the options (that also allows them to be in arbitrary order):

#!/usr/bin/env bash

while getopts cp:s: option; do
    case $option in
    c)
        echo "-c used"
        ;;
    p)
        echo "-p used with argument $OPTARG"
        ;;
    s)
        echo "-s used with argument $OPTARG"
        ;;
    *)
        echo "unknown option used"
        exit 1
        ;;
    esac
done

shift $(( OPTIND - 1 ));

echo "Arguments left after options processing: $@"

Now if you run this:

$ ./test.sh -c -p '$' -s 10 file.txt
-c used
-p used with argument $
-s used with argument 10
Arguments left after options processing: file.txt
0

If you want to get the filename in your script ./run. Then you can just use $# to get the total of the parameters. And so you can write as below:

eval filename=\$$#

If you just want to get the filename from a line like this: ./run ** ** ** ** file.txt

You can just use awk as below:

line="./run ** ** ** ** file.txt"
echo $line | awk '{print $NF}'

Good Luck!

Not the answer you're looking for? Browse other questions tagged or ask your own question.