поведение и существенная структура списка аргументов bash - PullRequest
0 голосов
/ 04 июня 2019

Пример кода ниже демонстрирует, что arglist / arguments можно легко проверить с помощью однострочной команды printf, тогда как массив, созданный из аргументов, нельзя проверить с помощью той же команды. И это напоминает нам, что «переменный» подход теряет различие между отдельными аргументами, если какой-либо аргумент содержит пробел.

Есть ли способ скопировать список сценариев в новый объект, который можно проверить с помощью этой однострочной команды printf?

Является ли список аргументов скрипта идентичным по своей структуре и поведению любому объекту (аналог массиву, переменной и т. Д.), Который можно создать в скрипте bash?

#!/bin/bash
# Only for demonstration purposes, override all arguments. 
set -- 'The dog ate the "mouse" ' but the cat?
# Create an array from script arguments.
declare -a argarray=( "$@" )
# Create a variable from script arguments.
argvariable="$@"

# Various ways of trying to inspect script arguments.
printf 'arguments:%s\n' "$@"
declare -p @
printf 'arguments, loop:\n'
countargs="0"
for x in "${@}"
do
    countargs=$(printf '%s\n' "1+$countargs" | bc)
    printf '%s\n' "$countargs: '$x'"
done
printf '\n'

# Various ways of trying to inspect argarray.
printf 'argarray:%s\n' "$argarray"
declare -p argarray
printf 'argarray, loop:\n'
countargs="0"
for x in "${argarray[@]}"
do
    countargs=$(printf '%s\n' "1+$countargs" | bc)
    printf '%s\n' "$countargs: '$x'"
done
printf '\n'


# Various ways of trying to inspect argvariable.
printf '\n'
printf 'argvariable:%s\n' "$argvariable"
declare -p argvariable 
printf 'argvariable in curly brackets, loop:\n'
countargs="0"
for x in "${argvariable[@]}"
do
    countargs=$(printf '%s\n' "1+$countargs" | bc)
    printf '%s\n' "$countargs: '$x'"
done

printf 'argvariable not bracketed, loop:\n'
countargs="0"
for x in $argvariable
do
    countargs=$(printf '%s\n' "1+$countargs" | bc)
    printf '%s\n' "$countargs: '$x'"
done

Ответы [ 3 ]

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

Является ли список аргументов скрипта по своей структуре и поведению идентичным любому объекту (аналог массива, переменной и т. Д.), Который можно создать в скрипте bash?

Да и нет.Есть сходства, в основном с массивом.Давайте попробуем создать список и сравнить аргументы с массивом arr:

  • получить количество аргументов: $# vs ${#arr[@]}
  • access ex.3-й аргумент / элемент: $3 против ${arr[3]}
  • доступ к n-му аргументу / элементу: ${@:$n:1} против ${arr[$n]}.Но нарезка массивов будет работать и для массивов: ${arr[@]:$n:1}.
  • установить n-й аргумент: Бух, вам нужно будет сделать set -- ${@:1:$((n-1))} newvalue ${@:$((n+1))} против arr[$n]=newvalue
  • , сдвиг вправо: shift илиНу, set -- "${@:2}" против arr=("${arr[@]:1}")
  • аргумент всегда непрерывен $0 $1 $2, тогда как вы можете arr=(); arr[10]=value; arr[100]=value.
  • получать индексы: что-то не так $(seq $#) vs ${!arr[@]}
  • получить правильный экранирование: "$@" vs "${arr[@]}"
  • получить в виде одной строки: "$*" vs "${arr[*]}"

Подводя итог:

  • Аргументы в скриптах должны быть доступны с помощью $@ и $<number>.
  • Вы можете работать с $@ во многом как с массивами, но вы можетене легко назначать и / или удалять элементы.
  • Существует также специальная команда shift, которая сдвигает аргументы.
  • «Специальные параметры» $@ $* * 1065Команды * и $<number> и shift и set задаются POSIX shell .Массивы Bash доступны только для bash.

К вашему сценарию:

  • argvariable="$@" расширяет $@ и присоединяет его, используя IFS.Таким образом, вы закончите одной строкой.Это равно argvariable="$*".Таким образом, экранирование аргументов потеряно.
  • countargs="0" for x in "${@}" do countargs=$(printf '%s\n' "1+$countargs" | bc) printf '%s\n' "$countargs: '$x'" done это можно просто упростить до подсчета ex.переводы строки с print %.0s вывод: countargs=$(printf "%.0s\n" "$@" | wc -l).В качестве альтернативы вы можете воспользоваться простой функцией справки: cntarg() { echo "$#"; }; countargs=$(cntarg "$@").Выполнение $(printf '%s\n' "1+$countargs" | bc) является избыточным - оболочка поддерживает команду expr, а bash поддерживает арифметическое расширение $((...)).Вы можете просто countargs=$((countargs+1)) или даже ((countargs++)) для увеличения переменной.
  • "${argvariable[@]}" - argvariable не является массивом.Выполнение "${argvariable[@]}" равно "$argvariable".

Есть ли способ скопировать список сценариев в новый объект, который можно проверить с помощью этой однострочной команды printf?

Сохраните список в массив, как вы делаете это с помощью команды declare -a argarray=.

argarray=("$@")

После этого вы можете обращаться к argarray и работать с ним так же, как $@.

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

Ответ на

Есть ли способ скопировать список сценариев в новый объект, который можно проверить с помощью этой однострочной команды printf?

однозначно: «Да. Используйте массив, но делайте это правильно». Самый важный недостаток в моем примере кода был следующим

printf 'argarray:%s\n' "$argarray"

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

Обратите внимание, что для массива еще один способ проверки элементов, не , доступный с самими аргументами, - declare -p argarray.

Меньшие недостатки, теперь исправленные благодаря ответам, были

  1. Метод "перерасхода" для увеличения отсчетов
  2. Мой неточный термин "переменная", когда "строка" была бы понятнее
  3. Не давая понять, что я хотел не только узнать общее количество аргументов, но и отобразить их числовые индексы.

Я держу «строковую» обработку внизу этого примера кода, как напоминание о том, что превращение аргументов в строку - плохая идея.

#!/bin/bash
# Only for demonstration purposes, override all arguments. 
set -- 'The dog ate the "mouse" ' but the cat?
# Create an array from script arguments.
declare -a argarray=( "$@" )
# Create a variable from script arguments.
argstring="$@"

# Various ways of trying to inspect script arguments.
printf 'arguments, printf:%s\n' "$@"
declare -p @
printf 'arguments indexed, loop:\n'
countargs="0"
for x in "${@}"
do
    countargs=$((countargs+1));
    printf '%s\n' "$countargs: '$x'"
done
printf '\n'

# Various ways of trying to inspect argarray.
printf 'argarray, printf:%s\n' "${argarray[@]}"
declare -p argarray
printf 'argarray indexed, loop:\n'
countargs="0"
for x in "${argarray[@]}"
do
    countargs=$((countargs+1));
    printf '%s\n' "$countargs: '$x'"
done
printf '\n'

# Various ways of trying to inspect argstring.
printf 'argstring, printf:%s\n' "$argstring"
declare -p argstring
printf 'argstring indexed, curly brackets, loop:\n'
countargs="0"
for x in "${argstring[@]}"
do
    countargs=$((countargs+1));
    printf '%s\n' "$countargs: '$x'"
done
printf 'argstring indexed, not bracketed, loop:\n'
countargs="0"
for x in $argstring
do
    countargs=$((countargs+1));
    printf '%s\n' "$countargs: '$x'"
done
printf '\n'

Результат:

> bash-example.sh
arguments, printf:The dog ate the "mouse" 
arguments, printf:but
arguments, printf:the
arguments, printf:cat?
/Users/BNW/u/kh/bin/bash-example.sh: line 11: declare: @: not found
arguments indexed, loop:
1: 'The dog ate the "mouse" '
2: 'but'
3: 'the'
4: 'cat?'

argarray, printf:The dog ate the "mouse" 
argarray, printf:but
argarray, printf:the
argarray, printf:cat?
declare -a argarray='([0]="The dog ate the \"mouse\" " [1]="but" [2]="the" [3]="cat?")'
argarray indexed, loop:
1: 'The dog ate the "mouse" '
2: 'but'
3: 'the'
4: 'cat?'

argstring, printf:The dog ate the "mouse"  but the cat?
declare -- argstring="The dog ate the \"mouse\"  but the cat?"
argstring indexed, curly brackets, loop:
1: 'The dog ate the "mouse"  but the cat?'
argstring indexed, not bracketed, loop:
1: 'The'
2: 'dog'
3: 'ate'
4: 'the'
5: '"mouse"'
6: 'but'
7: 'the'
8: 'cat?'

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

В ответ на вопрос «Есть ли способ скопировать список сценариев в новый объект, который можно проверить с помощью этой однострочной команды printf?»:

после

set -- 'The dog ate the "mouse" ' but the cat\?

код

argarray=( "$@" )
printf 'arguments:%s\n' "${argarray[@]}"

выдает точно такой же результат, как и

printf 'arguments:%s\n' "$@"

Относительно «Список аргументов скрипта идентичен по своей структуре и поведению какому-либо объекту (аналог массиву, переменной и т. Д.), Который можно создать в скрипте bash?», Ближайший «объект» к список аргументов ( позиционные параметры ) - это массив. Массивы значительно мощнее, хотя. Например, элементы массива могут быть добавлены, установлены или удалены по отдельности; и массивы могут быть редкими. См. Позиционные параметры (Справочное руководство Bash) и Массивы (Справочное руководство Bash) .


Обратите внимание, что подсчитанный список элементов массива можно распечатать с помощью:

arg_idx=0
for arg in "${argarray[@]}" ; do
    printf "%d: '%s'\\n" $((++arg_idx)) "$arg"
done
...