Удалить последний аргумент из списка аргументов оболочки script (bash)

Этот вопрос касается bash script, который запускается в osx automator. Я использую действия automator, чтобы получить и отфильтровать кучу ссылок на файл от искателя. Затем я добавляю к этому списку имя родительской папки, также через действие автомата. Затем Automator передает эти аргументы в действие под названием "run shell script". Я точно не знаю, как automator вызывает script, но список аргументов выглядит так, как показано на экране: echo "[email protected]"

/Объемы/G-рейд/Онлайн/WAV_TEST/Testbok 50/01/01000 43-001.wav/Объемы/G-рейд/Онлайн/WAV_TEST/Testbok 50/02/02000 43-002.wav/Тома/G-Raid/Online/WAV_TEST/Testbok 50/03/03000 43-003.wav/Объемы/G-рейд/Онлайн/WAV_TEST/Testbok 50

В этом случае путь к 3 файлам и папке.

В оболочке script запускаю приложение с именем ripcheckc * с аргументами, переданными от автомата минус последний аргумент (папка) в списке.

Я использую это, чтобы удалить последний аргумент:

_args=( "[email protected]" )
unset _args[${#_args[@]}-1]

И это echo $_args:

/Объемы/G-рейд/Онлайн/WAV_TEST/Testbok 50/01/01000 43-001.wav/Объемы/G-рейд/Онлайн/WAV_TEST/Testbok 50/02/02000 43-002.wav/Тома/G-Raid/Online/WAV_TEST/Testbok 50/03/03000 43-003.wav

То же, что и раньше, но без папки.

Теперь, если я запустил ripcheckc с аргументом "[email protected]" в качестве аргумента, он работает (но позже не будет из-за этого последнего пути в списке аргументов). Если я использую ${_args[@]}, приложение будет просто отменено молча. Когда я эхо [email protected] и _args, результат выглядит идентичным, за исключением последнего аргумента.

Мой вопрос: в чем разница между [email protected]и $_args, которые делают первый допустимый ввод, а второй не?

* Приложение ripcheckc

Надеюсь, мой вопрос имеет смысл.

EDIT: разрешено.

Ответ 1

Предполагая, что у вас уже есть array, вы можете сказать:

unset "array[${#array[@]}-1]"

Например, если ваш скрипт содержит:

array=( "[email protected]" )
unset "array[${#array[@]}-1]"    # Removes last element -- also see: help unset
for i in "${array[@]}"; do
  echo "$i"
done

вызывая его с помощью: bash scriptname foo bar baz производит:

foo
bar

Ответ 2

Я использовал этот однострочник bash раньше

set -- "${@:1:$(($#-1))}"

Он устанавливает список аргументов в текущий список аргументов, за исключением последнего аргумента.


Как это устроено:

  • $# это количество аргументов
  • $((...)) является арифметическим выражением, поэтому $(($#-1)) на единицу меньше количества аргументов.
  • ${variable:position:count} является выражением подстроки: оно извлекает count символов из variable начинающейся с позиции. В особом случае, когда variable равна @, что означает список аргументов, она извлекает count аргументов из списка, начинающегося с position. Здесь position равна 1 для первого аргумента, а count на единицу меньше количества аргументов, разработанных ранее.
  • set -- arg1...argn устанавливает список аргументов для заданных аргументов

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

Ответ 3

Вы также можете получить все, кроме последнего аргумента, с помощью

"${@:0:$#}"

что, честно говоря, немного отрывочно, поскольку, как представляется, (ab) используется тот факт, что аргументы нумеруются начиная с 1, а не 0.

Обновление: это работает только из-за ошибки (исправлено не ранее 4.1.2) при обработке [email protected]. Он работает в версии 3.2.