Parsing a string with quotes in GETOPTS

好久不见. 提交于 2019-12-25 01:05:10

问题


I am trying to accept a space delimited string in place of $OPTARG while parsing an option

For example

./script -k '1 2 ad'ias'

As seen the third string can contain any special character. Is there a way that I can overlook the quote in between as I want to parse the entire string and process some options

Tried inserting the \ character but that does not work for my case because I cannot insert any character in my string.


while getopts "a:k:" option
do
   echo "${option}"
   case ${option} in
     a)
        function_a ${OPTARG}   # <-- no quotes
      ;;
     k)
        function_k "${OPTARG}" # <-- quotes
      ;;
   esac
done

回答1:


I'm not sure I fully understand what the difficulty is; handling strings with special characters is a bit tricky, but (except the NUL character) basically doable. The main things to watch out for are:

  • When you represent a string literal (in a script, or when passing arguments to a script), you must use a valid shell representation of that string, not just the raw string. For example, suppose you want to pass/use this string:

    12 34 kla#42@!' 2 M$" rtqas;::#
    

    There are a number of ways of representing this string for use in a shell script or command line. You can leave it unquoted but escape the individual special characters, like this:

    12\ 34\ kla\#42@\!\'\ 2\ M\$\"\ rtqas\;::\#
    

    Or you could wrap it in double-quotes, and escape just those characters that retain special meaning inside double-quotes (that is, double-quotes, backquotes, and dollar signs, and if it's a bash interactive shell exclamation marks):

    "12 34 kla#42@!' 2 M\$\" rtqas;::#"    # For a non-interactive shell
    "12 34 kla#42@\!' 2 M\$\" rtqas;::#"   # For an interactive shell
    

    If it didn't contain single-quotes, you could single-quote it; since it does, you can't use that method. But you can mix methods, e.g. using single-quotes around the parts that don't contain single-quotes and escaping or double-quoting the single quote:

    '12 34 kla#42@!'\'' 2 M$" rtqas;::#'    # Single-quote is escaped
    '12 34 kla#42@!'"'"' 2 M$" rtqas;::#'   # Single-quote is double-quoted
    

    In bash (but not some other shells), there's also ANSI-C-escaped strings, written with $' ... ':

    $'12 34 kla#42@!\' 2 M$" rtqas;::#'    # Single-quote is the only character that needs escaping
    

    Note that all of the above are just different ways of representing the exact same string; once the shell parses it, it comes out the same from any of them. You can use whatever's convenient, but you must use a syntactically valid representation of the string.

  • Once the string is stored in a parameter/variable, you must put double-quotes around references to that variable. In most shell contexts, when a variable is used without quotes, the shell will split it into words (based on spaces or whatever's in IFS), and try to expand anything that looks like a file wildcard; you don't want this. But if it's in double-quotes, the variable gets expanded and no further parsing is done, it's just passed through unmolested.

    Actually, you should almost always double-quote variable references in shell scripts even if you don't expect them to contain special characters. We see so many shell questions here that have the answer "if you double-quoted your variable references, you wouldn't have this problem"...

Here's an example, based on your script:

#!/bin/bash

printopt() {
   printf '%s value is: <<%s>>\n' "$1" "$2"    # Double-quotes required here
}

while getopts "a:k:" option
do
   case "${option}" in    # This is one of the few places it's safe to leave off double-quotes. But they don't hurt.
     a)
        printopt "-a" "${OPTARG}"    # Double-quotes required here
      ;;
     k)
        printopt "-k" "${OPTARG}"    # Double-quotes required here
      ;;
   esac
done

And running it with various representations of strings:

$ ./argtest.sh -a 12\ 34\ kla\#42@\!\'\ 2\ M\$\"\ rtqas\;::\# -k "1 2 ad'ias"
-a value is: <<12 34 kla#42@!' 2 M$" rtqas;::#>>
-k value is: <<1 2 ad'ias>>
$ ./argtest.sh -a '12 34 kla#42@!'"'"' 2 M$" rtqas;::#' -k $'1 2 ad\'ias'
-a value is: <<12 34 kla#42@!' 2 M$" rtqas;::#>>
-k value is: <<1 2 ad'ias>>

Ok, ok, there are a few situations where it's more complicated than that:

  • There are some situations where a string will be run through the shell parsing process multiple times, such as when it's being run over ssh (the command gets processed by the local shell, passed to the remote computer, then processed by that shell and executed), or used as a shell alias (the alias command gets parsed, result stored, then parsed again when you use it). In these cases, you essentially need two (or possibly more) layers of quoting/escaping: take the raw string, quote/escape by any of the above methods, then take that string and quote/escape that (probably by a different method).

  • Some versions of echo will parse escape (backslash) sequences in the string (using different rules than the shell itself does), which can cause confusion. I recommend using printf instead when this might be an issue; the only problem is that it's more complex than echo: it doesn't just print its arguments, it uses the first argument is a format string which controls how the rest of the arguments are printed. See my examples in the script above.

  • If you are passing the string to another script that doesn't use double-quotes around its parameter & variable references, you are doomed. In this case, the only thing that can be done is to fix that other script.



来源:https://stackoverflow.com/questions/55623092/parsing-a-string-with-quotes-in-getopts

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!