Как мне использовать $ *, опуская некоторые входные переменные, такие как $ 1 и $ 2 в скрипте bash?

15

Например,

elif [[ $append = $1 ]]
then
  touch ~/directory/"$2".txt
  echo "$variable_in_question" >> ~/directory/"$2".txt

либо создать текстовый файл, содержащий все входные данные "$2", либо добавить существующий текстовый файл со всеми входными данными "$2", что бы я использовал вместо "$variable_in_question"строки 4?

Я в принципе хочу "$*", но опускаю "$1"и "$2".

Oreoplasm
источник

Ответы:

32

Вы можете использовать bashрасширение параметров, чтобы указать диапазон, это также работает с позиционными параметрами. Для $3... $nэто будет:

"${@:3}" # expands to "$3" "$4" "$5" …
"${*:3}" # expands to "$3 $4 $5 …"

Имейте в виду, что оба $@и $*игнорируйте первый аргумент $0. Если вам интересно, какой из них использовать в вашем случае: очень вероятно, что вы хотите цитаты $@. Не используйте, $*если вы явно не хотите, чтобы аргументы цитировались индивидуально.

Вы можете попробовать это следующим образом:

$ bash -c 'echo "${@:3}"' 0 1 2 3 4 5 6
3 4 5 6
$ echo 'echo "${@:3}"' >script_file
$ bash script_file 0 1 2 3 4 5 6
2 3 4 5 6

Обратите внимание, что в первом примере $0заполняется первый аргумент, 0а при использовании в скрипте $0вместо этого заполняется именем скрипта, как показано во втором примере. Имя сценария, bashконечно же, является первым аргументом, просто он обычно не воспринимается как таковой - то же самое относится и к сценарию, который исполняется и называется «напрямую». Итак, в первом примере мы имеем $0= 0, $1= 1и т. Д., А во втором это $0= script_file, $1= 0, $2= и 1т. Д .; ${@:3}выбирает каждый аргумент, начинающийся с $3.

Некоторые дополнительные примеры для возможных диапазонов:

 # two arguments starting with the third
$ bash -c 'echo "${@:3:2}"' 0 1 2 3 4 5 6
3 4
 # every argument starting with the second to last one
 # a negative value needs either a preceding space or parentheses
$ bash -c 'echo "${@: -2}"' 0 1 2 3 4 5 6
5 6
 # two arguments starting with the fifth to last one
$ bash -c 'echo "${@:(-5):2}"' 0 1 2 3 4 5 6
2 3

Дальнейшее чтение:

Десерт
источник
27

Вы можете использовать shiftвстроенный:

$ help shift
shift: shift [n]
    Shift positional parameters.

    Rename the positional parameters $N+1,$N+2 ... to $1,$2 ...  If N is
    not given, it is assumed to be 1.

    Exit Status:
    Returns success unless N is negative or greater than $#.

Ex. данный

$ cat argtest.bash 
#!/bin/bash

shift 2

echo "$*"

тогда

$ ./argtest.bash foo bar baz bam boo
baz bam boo
steeldriver
источник
3
@ Oreoplasm Я думаю, стоит упомянуть, что такой shiftподход сделает невозможным доступ, $1и $2после того, как вы их изменили. В вашем сценарии, который вы используете $2вместе с $variable_in_question, вам нужно либо изменить это, либо использовать подход расширения параметров.
десерт
6
shiftхорошо, когда первые один или несколько аргументов являются особыми, и имеет смысл выделить их в отдельные переменные ( foo="$1"; bar="$2";или if [[ something with $1 ]];then blah blah; shift. Но ответ @sert с неразрушающим подходом хорош в других случаях, когда вам все еще нужен полный список позже или при использовании любителя синтаксис , чтобы выбрать ограниченный диапазон аргументов, а не до бесконечности, без введения пустой арг в команду , если $@не имеет , что многие элементов.
Питер Кордес
13

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

Например, если мне нужны все аргументы, кроме первого, четвертого и пятого:

args=( "$@" )
unset args[0] args[3] args[4]
echo "${args[@]}"

В копии индексы смещены на 1, поскольку $0не являются частью $@.

Мур
источник
1
Конечно, это можно объединить, например, echo "${args[@]:2}"для третьего до последнего аргумента.
десерт