Разбор строки с кавычками в GETOPTS - PullRequest
0 голосов
/ 11 апреля 2019

Я пытаюсь принять строку с пробелом вместо $ OPTARG при разборе параметра

Например,

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

Как видно, третья строка может содержать любой специальный символ.Есть ли способ, которым я могу пропустить кавычку между, так как я хочу проанализировать всю строку и обработать некоторые параметры

Попытка вставки символа \, но это не работает для моего случая, потому что я не могу вставить любой символ вмоя строка.


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 Ответ

2 голосов
/ 11 апреля 2019

Я не уверен, что полностью понимаю, в чем проблема; обработка строк со специальными символами немного сложна, но (кроме символа NUL) в принципе выполнима. Основные вещи, на которые стоит обратить внимание:

  • Когда вы представляете строковый литерал (в сценарии или при передаче аргументов в сценарий), вы должны использовать действительную оболочку представление этой строки, а не только необработанную строку. Например, предположим, что вы хотите передать / использовать эту строку:

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

    Существует несколько способов , представляющих эту строку для использования в сценарии оболочки или командной строке. Вы можете оставить его без кавычек, но экранировать отдельные специальные символы, например:

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

    Или вы можете заключить его в двойные кавычки и экранировать только те символы, которые имеют особое значение внутри двойных кавычек (то есть двойные кавычки, обратные кавычки и знаки доллара, а также, если это интерактивные восклицательные знаки в bash) :

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

    Если в нем нет одинарных кавычек, вы можете его заключить в одинарные кавычки; поскольку это так, вы не можете использовать этот метод. Но вы можете смешивать методы, например, использование одинарных кавычек вокруг частей, которые не содержат одинарных кавычек, и экранирование или двойные кавычки в одинарных кавычках:

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

    В bash (но не в некоторых других оболочках) есть также экранированные ANSI-C строки, записанные с $' ... ':

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

    Обратите внимание, что все вышеперечисленное - это просто разные способы представления одной и той же строки; после того, как оболочка проанализирует его, он получит то же самое от любого из них. Вы можете использовать все, что вам удобно, но вы должны использовать синтаксически правильное представление строки.

  • Как только строка сохраняется в параметре / переменной, вы должны помещать двойные кавычки вокруг ссылок на эту переменную. В большинстве контекстов оболочки, когда переменная используется без кавычек, оболочка разделяет ее на слова (на основе пробелов или чего-либо еще в IFS) и пытается раскрыть все, что похоже на подстановочный знак файла; ты не хочешь этого. Но если она заключена в двойные кавычки, переменная раскрывается и дальнейший разбор не выполняется , она просто передается через unmoled.

    На самом деле, вы почти всегда должны заключать в кавычки переменные ссылки в кавычках, даже если вы не ожидаете, что они будут содержать специальные символы. Мы видим так много вопросов оболочки, на которые есть ответ: «Если вы дважды заключите в кавычки переменные, у вас не возникнет этой проблемы» ...

Вот пример, основанный на вашем скрипте:

#!/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

И запуск его с различными представлениями строк:

$ ./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>>

Хорошо, хорошо, есть несколько ситуаций, где это сложнее:

  • В некоторых случаях строка будет проходить через процесс разбора оболочки несколько раз, например, когда она выполняется через ssh (команда обрабатывается локальной оболочкой и передается на удаленный компьютер, затем обрабатывается этой оболочкой и выполняется) или используется в качестве оболочки alias (команда alias анализируется, сохраняется результат, а затем снова анализируется при его использовании). В этих случаях вам, по сути, понадобится два (или, возможно, больше) слоя цитирования / экранирования: взять необработанную строку, заключить в кавычки / escape любым из вышеперечисленных методов, затем взять эту строку и укажите / побег , что (возможно, другим способом).

  • Некоторые версии echo будут анализировать escape-последовательности (обратную косую черту) в строке (используя другие правила, чем сама оболочка), что может вызвать путаницу. Я рекомендую использовать printf вместо этого, когда это может быть проблемой; единственная проблема в том, что он более сложный, чем echo: он не просто печатает свои аргументы, он использует первый аргумент - строку формата, которая контролирует, как выводятся остальные аргументы. Смотрите мои примеры в приведенном выше сценарии.

  • Если вы передаете строку другому сценарию, который не использует двойные кавычки вокруг ссылок на параметры и переменные, вы обречены.В этом случае единственное, что можно сделать, это исправить этот другой скрипт.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...