0

I am attempting to parse the parameters sent to shell script. For example the values sent to the script are as follows:

-to someone@somewhere.com -a file1.txt file2.txt "new file.txt"

I can parse the string so that I get -a as my operator, but I want to reformat the parameter part file1.txt file2.txt "new file.txt" so that it looks like 'file1.txt' 'file2.txt' 'new file.txt' so that I can pass it down to the zip utility.

Right now I am using the following to parse the parameter, but it is not getting me the results I want. It is close but not quite right.

for file in `echo $PARM`
do
  FILE_LIST="$FILE_LIST '"$file"'"
done

This gives me 'file1.txt' file2.txt' 'new' 'file.txt' How can I rework the above code to give me what I want. Thank you

jub0bs
  • 60,866
  • 25
  • 183
  • 186
user1524133
  • 191
  • 5
  • 1
    zip? show complete example. http://xyproblem.info/ – Karoly Horvath Jan 22 '16 at 22:00
  • 2
    Please show how do you assign the value to the `PARM`. – Oleg Andriyanov Jan 22 '16 at 22:03
  • 2
    This is not a good starting point for passing filenames to `zip`. The single quotes are shell syntax, and can not be put as literals in a string to pass to zip. Use an array instead. – that other guy Jan 22 '16 at 22:11
  • 1
    You shouldn't have to "parse" the string at all. Each of these is a separate parameter to your script; `${1}` would be `-to`, `${2}` would be `someone@somewhere.com` etc. so `new file.txt` with the space in it is a single parameter. The challenge is to not break it into 2 params when you pass it on to your zip command line. Quoting it `"${6}"` should be enough... but you don't know the number -- take a look at the `getopt(1)` command and the shell-builtin `shift`, and using `${@}`, especially `${1+"$@"}` for old shells - See http://unix.stackexchange.com/q/68484/1986 – Stephen P Jan 22 '16 at 22:27
  • BTW, this is BashFAQ #50: http://mywiki.wooledge.org/BashFAQ/050 – Charles Duffy Jan 23 '16 at 01:57
  • 1
    ...basically: Quotes in shell are **syntax**, not **literal data**. You absolutely don't want to put quotes in your data thinking they'll change how syntax parsing works: They don't/won't (if your code is following good practices), and if you do ugly things like `eval` to *force* your data to be parsed as syntax, you're opening up security holes. – Charles Duffy Jan 23 '16 at 02:01

1 Answers1

1

First, you need to understand the sequence of operations when the shell parses a command line. Here's a partial list: first, it interprets quotes and escapes, then removes them (after they've had their effects), then expands any variable references (and similar things like backquote expressions), word-splits and wildcard-expands the expanded variable values, then finally treats the result of all of that as a command and its arguments.

This has two important implications for what you're trying to do: by the time your script receives its arguments, they no longer have quotes; the quotes have had their effect (new file.txt is a single argument rather than two), but the quotes themselves are gone. Also, when putting quotes in a variable is useless because by they time the variable gets expanded and the quotes are part of the command line, it's too late for them to do anything useful -- they aren't parsed as quotes, they're just passed on to the command as part of the argument (which you don't want).

Fortunately, the answer is easy (and Stephen P summarized it in his comment): put double-quotes around all variable references. This prevents the word-splitting and wildcard-expansion phases from messing with their values, which means that whatever was passed to your script as a single argument (e.g. new file.txt) gets passed on as a single argument. If you need to pass on all of your arguments, use "$@". If you need to pass on only some, you can either use shift to get rid of the options and then "$@" will pass on the remaining ones, or use e.g. "${@:4}" to pass all argument starting at #4, or "${@:4:3}" to pass on three arguments starting at #4.

Gordon Davisson
  • 118,432
  • 16
  • 123
  • 151