0 Вопрос: Использовать пользовательскую команду в строке [дубликата]

вопрос создан в Wed, May 8, 2019 12:00 AM

Я столкнулся с проблемой передачи аргумента команде в сценарии Bash.

poc.sh:

#!/bin/bash

ARGS='"hi there" test'
./swap ${ARGS}

своп:

#!/bin/sh
echo "${2}" "${1}"

Текущий вывод:

there" "hi

Меняя только poc.sh (так как я считаю, что swap делает то, что я хочу правильно), как мне заставить poc.sh передать «hi there» и проверить как два аргумента, при этом «hi there» без кавычек это?

    
5
  1. Это тема BashFAQ # 50: mywiki.wooledge.org/BashFAQ/050
    2014-09-26 21: 22: 47Z
3 ответа                              3                         

Несколько вступительных слов

Если это вообще возможно, не используйте строки в кавычках в качестве формата ввода.

  • Сложно анализировать последовательно: разные оболочки имеют разные расширения, а разные реализации, не относящиеся к оболочке, реализуют разные подмножества (см. подробности между shlex и xargs ниже).
  • Трудно создать программно. У ksh и bash есть printf '%q', который сгенерирует строку в кавычках с содержимым произвольной переменной, но в стандарте POSIX sh такого эквивалента не существует.
  • Легко разобрать плохо . Многие пользователи, использующие этот формат, используют eval, что связано с серьезными проблемами безопасности.

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

xargs, с исками

Если вы получаете список аргументов из источника ввода, созданного человеком, используя кавычки оболочки, вы можете использовать xargs для его анализа. Рассмотрим:

array=( )
while IFS= read -r -d ''; do
  array+=( "$REPLY" )
done < <(xargs printf '%s\0' <<<"$ARGS")

swap "${array[@]}"

... поместит проанализированный контент $ARGS в массив array. Если вы хотите вместо этого прочитать файл, замените <filename на <<<"$ARGS".

xargs, POSIX-совместимый

Если вы пытаетесь написать код, совместимый с POSIX sh, это становится сложнее. (Я собираюсь предположить, что здесь вводится файл для упрощения):

# This does not work with entries containing literal newlines; you need bash for that.
run_with_args() {
  while IFS= read -r entry; do
    set -- "$@" "$entry"
  done
  "$@"
}
xargs printf '%s\n' <argfile | run_with_args ./swap

Эти подходы более безопасны, чем запуск xargs ./swap <argfile, поскольку они вызовут ошибку, если будет больше или больше аргументов, которые могут быть учтены, вместо запуска лишних аргументов в качестве отдельных команд.

Python shlex - а не xargs - с оскорблениями

Если вам требуется более точный анализ POSIX sh, чем у xargs, рассмотрите возможность использования вместо этого модуля Python shlex:

shlex_split() {
  python -c '
import shlex, sys
for item in shlex.split(sys.stdin.read()):
    sys.stdout.write(item + "\0")
'
}
while IFS= read -r -d ''; do
  array+=( "$REPLY" )
done < <(shlex_split <<<"$ARGS")
    
17
2018-03-02 23: 54: 44Z
  1. Кажется, это не работает с ARGS="\"a\\\"b\" c"? Об ошибке xargs: непревзойденная двойная кавычка; по умолчанию кавычки являются специальными для xargs, если вы не используете опцию -0
    2016-12-25 22: 03: 12Z
  2. Справедливая точка - xargs действительно не учитывает поведение POSIX sh в этом случае. Обновление с использованием альтернативы с использованием функции Python 2 shlex.split().
    2016-12-26 18: 51: 12Z
  3. Лучшее, что можно сделать, - это вернуть OP на правильный путь: если OP нуждается в такой вещи, то их дизайн явно неправильный. Если OP не пишет оболочку (или cli), в этом случае выбор языка неправильный. В любом случае, OP делает это неправильно.
    2016-12-26 19: 03: 36Z
  4. @ gniourf_gniourf, ... теоретически я согласен. На практике людям, как правило, предъявляют требования, которые не имеют смысла (или нуждаются в совместимости с давними системами /практиками - существует тонна устаревшего начального экрана).ipts для приложений Java, плавающих вокруг, которые полагаются на evaling списки аргументов, данные в форме в кавычках), и есть смысл в том, чтобы быть в состоянии вынести лучшее из плохой ситуации ... хотя, конечно, "не делай этого" должно быть часть данного совета.
    2016-12-26 19: 06: 31Z
  5. @ gniourf_gniourf, ... Я редактировал в соответствующем введении.
    2016-12-26 19: 09: 25Z

Встроенные кавычки не защищают пробелы; к ним относятся буквально. Используйте массив в bash:

args=( "hi there" test)
./swap "${args[@]}"

В оболочке POSIX вы застряли, используя eval (именно поэтому большинство оболочек поддерживают массивы).

args='"hi there" test'
eval "./swap $args"

Как обычно, очень убедитесь, что вы знаете содержимое $args и понимаете, как полученная строка будет проанализирована перед использованием eval.

    
3
2014-09-26 19: 53: 42Z
  1. Я склонен утверждать, что здесь есть больше опций, чем eval. Даже в POSIX можно было прочитать "$@" из xargs.
    2015-07-17 23: 07: 50Z

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

## demonstration matching the question
$ ( ARGS='"hi there" test' ; ./swap ${ARGS} )
there" "hi

## simple solution, using 'xargs'
$ ( ARGS='"hi there" test' ; echo ${ARGS} |xargs ./swap )
test hi there
    
0
2017-03-10 23: 15: 47Z
  1. Комментарий: обработка строки Bash чрезвычайно запутана. xargs удаляет догадки, передавая параметры непосредственно через exec , который обходит нормальный, капризный обработка строк, которую Bash в противном случае выполнял бы как часть обработки командной строки на основе строк.
    2017-04-01 18: 13: 16Z
  2. Я не могу быть уверен в своем утверждении относительно exec. Но я придерживаюсь своего утверждения, что «Обработка строки Bash чрезвычайно запутанная» .
    2017-04-01 18: 23: 43Z
источник размещен Вот