$ (Printf '% q' "$ {@: 1}") эквивалентно "$ {*}"? - PullRequest

Ответы [ 2 ]

1 голос
/ 29 июня 2019

Нет, это не эквивалентно, потому что слова разделены.Ex.следующий код:

check_args() {
  echo "\$#=$#"
  printf "%s\n" "$@";
}

# setting arguments
set -- "space notspace" "newline"$'\n'"newline"
echo '1: ---------------- "$*"'
check_args "$*"

echo '2: ---------------- $(printf '\''%q '\'' "${@:1}")'
check_args $(printf '%q ' "${@:1}")

echo '3: ---------------- "$(printf '\''%q '\'' "${@:1}")"'
check_args "$(printf '%q ' "${@:1}")"

echo '4: ---------------- IFS=@ and "$*"'
( IFS=@; check_args "$*"; )

echo "5: ---------------- duplicating quoted"
check_args "$(printf '%s'"${IFS:0:1}" "${@:1}" | sed 's/'"${IFS:0:1}"'$//')"

echo "6: ---------------- duplicating quoted IFS=@"
( IFS=@; check_args "$(printf '%s'"${IFS:0:1}" "${@:1}" | sed 's/'"${IFS:0:1}"'$//')"; )

echo "7: ---------------- duplicating eval unquoted"
eval check_args $(printf '%q"'"${IFS:0:1}"'"' "${@:1}" | sed 's/'"${IFS:0:1}"'$//')

echo "8: ---------------- duplicating eval unquoted IFS=@"
( eval check_args $(IFS=@ ; printf '%q"'"${IFS:0:1}"'"' "${@:1}" | sed 's/"'"${IFS:0:1}"'"$//'); )

выведет:

1: ---------------- "$*"
$#=1
space notspace newline
newline
2: ---------------- $(printf '%q ' "${@:1}")
$#=3
space\
notspace
$'newline\nnewline'
3: ---------------- "$(printf '%q ' "${@:1}")"
$#=1
space\ notspace $'newline\nnewline'
4: ---------------- IFS=@ and "$*"
$#=1
space notspace@newline
newline
5: ---------------- duplicating quoted
$#=1
space notspace newline
newline
6: ---------------- duplicating quoted IFS=@
$#=1
space notspace@newline
newline
7: ---------------- duplicating eval unquoted
$#=1
space notspace newline
newline
8: ---------------- duplicating eval unquoted IFS=@
$#=1
space notspace@newline
newline

проверено на repl .

"$*" выводит аргументы, разделенные наМФС.Таким образом, как показано в тесте 4, если разделитель не сброшен или не установлен на пробел, то результат $* будет делимеризован IFS, @ в этом примере.

Также, если IFS не установлен или установлен в пробел, вывод $* не включает в себя завершающий пробел, в то время как printf '%q ' всегда будет печатать завершающий пробел в конце строки.

Вывод $(printf '%q ' "${@:1}") все еще разделен на пробел.Таким образом, контрольный пример 2 получает 3 аргумента, потому что строка space notspace разделена пробелом и разделена на два аргумента.При вложении printf внутрь " не поможет - printf подставляет ex.символы новой строки для \n символов.

Случаи 5, 6, 7, 8 - мои попытки повторить поведение "$*" с использованием printf.Это можно видеть в случаях 7 и 8, которые я использовал eval, в случаях 5 и 6 я цитировал подстановку команд.Выходные данные случаев (5 и 6) и (7 и 8) должны соответствовать выходным данным случаев 1 и 4 соответственно.

Для дублирования поведения "$*" Особое внимание необходимо уделить IFS, чтобы правильно разделить струны.Я использовал sed 's/'"${IFS:0:1}"'$//', чтобы удалить конечный разделитель IFS из вывода printf.Случаи 5 и 6 без кавычек $(printf ...) попытки, с 6 с использованием IFS=@, чтобы показать разделительные работы.Случаи 7 и 8 используют eval со специальной обработкой для IFS, потому что сам символ IFS должен быть заключен в кавычки, чтобы оболочка больше не разбивалась на него, поэтому printf '%q"'"${IFS:0:1}"'"'.

выполнение $ (printf '% q' "$ {@: 2}") (обратите внимание на 2 вместо 1, как раньше) невозможно с чистым bash $ *?

Возможно, вы могли бы просто переместить аргументы внутри подстановки $(shift; printf "%s\n" "$*"), но, как показано выше, они в любом случае не эквивалентны.

0 голосов
/ 30 июня 2019

Используя @ Kamil Cuk ответ в качестве основы, я построил этот новый тестовый код для иллюстрации, также доступен в repl :

#!/bin/bash
check_args() {
  echo "\$#=$#"
  local counter=0
  for var in "$@"
  do
      counter=$((counter+1));
      printf "$counter. '$var', ";
  done
  printf "\\n\\n"
}

# setting arguments
set -- "space notspace" "lastargument"; counter=1
echo $counter': ---------------- "$*"'; counter=$((counter+1))
check_args "$*"

echo $counter': ---------------- $*'; counter=$((counter+1))
check_args $*

echo $counter': ---------------- "$@"'; counter=$((counter+1))
check_args "$@"

echo $counter': ---------------- $@'; counter=$((counter+1))
check_args $@

echo $counter': ---------------- $(printf '\''%q '\'' "${@:1}")'; counter=$((counter+1))
check_args $(printf '%q ' "${@:1}")

echo $counter': ---------------- "$(printf '\''%q '\'' "${@:1}")"'; counter=$((counter+1))
check_args "$(printf '%q ' "${@:1}")"

echo $counter': ---------------- IFS=@ and "$*"'; counter=$((counter+1))
( IFS=@; check_args "$*"; )

echo "$counter: ---------------- duplicating quoted"; counter=$((counter+1))
check_args "$(printf '%s'"${IFS:0:1}" "${@:1}" | sed 's/'"${IFS:0:1}"'$//')"

echo "$counter: ---------------- duplicating quoted IFS=@"; counter=$((counter+1))
( IFS=@; check_args "$(printf '%s'"${IFS:0:1}" "${@:1}" | sed 's/'"${IFS:0:1}"'$//')"; )

echo "$counter: ---------------- duplicating eval unquoted"; counter=$((counter+1))
eval check_args $(printf '%q"'"${IFS:0:1}"'"' "${@:1}" | sed 's/'"${IFS:0:1}"'$//')

echo "$counter: ---------------- duplicating eval unquoted IFS=@"; counter=$((counter+1))
( eval check_args $(IFS=@ ; printf '%q"'"${IFS:0:1}"'"' "${@:1}" | sed 's/"'"${IFS:0:1}"'"$//'); )

->

GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu)
1: ---------------- "$*"
$#=1
1. 'space notspace lastargument',

2: ---------------- $*
$#=3
1. 'space', 2. 'notspace', 3. 'lastargument',

3: ---------------- "$@"
$#=2
1. 'space notspace', 2. 'lastargument',

4: ---------------- $@
$#=3
1. 'space', 2. 'notspace', 3. 'lastargument',

5: ---------------- $(printf '%q ' "${@:1}")
$#=3
1. 'space', 2. 'notspace', 3. 'lastargument',

6: ---------------- "$(printf '%q ' "${@:1}")"
$#=1
1. 'space\ notspace lastargument ',

7: ---------------- IFS=@ and "$*"
$#=1
1. 'space notspace@lastargument',

8: ---------------- duplicating quoted
$#=1
1. 'space notspace lastargument',

9: ---------------- duplicating quoted IFS=@
$#=1
1. 'space notspace@lastargument',

10: ---------------- duplicating eval unquoted
$#=1
1. 'space notspace lastargument ',

11: ---------------- duplicating eval unquoted IFS=@
$#=1
1. 'space notspace@lastargument',
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...