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

Этот вопрос касается скрипта bash, который запускается в autotor osx. Я использую действия автомата, чтобы получить и отфильтровать кучу ссылок на файлы из искателя. Затем я добавляю к этому списку имя родительской папки, также с помощью действия автомата. Затем Automator передает эти аргументы действию, называемому «запустить сценарий оболочки». Я точно не знаю, как автомат вызывает скрипт, но список аргументов выглядит так, когда повторяется с помощью: echo "$@"

/Volumes/G-Raid/Online/WAV_TEST/Testbok 50/01/01000 43-001.wav /Volumes/G-Raid/Online/WAV_TEST/Testbok 50/02/02000 43-002.wav /Volumes/G-Raid /Online/WAV_TEST/Тестбокс 50/03/03000 43-003.wav /Volumes/G-Raid/Online/WAV_TEST/Тестбокс 50

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

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

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

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

А это echo $_args:

/Volumes/G-Raid/Online/WAV_TEST/Testbok 50/01/01000 43-001.wav /Volumes/G-Raid/Online/WAV_TEST/Testbok 50/02/02000 43-002.wav /Volumes/G-Raid /Online/WAV_TEST/Тестбокс 03/50/03000 43-003.wav

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

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

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

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

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

РЕДАКТИРОВАТЬ: Решено.


person Nordanfors    schedule 05.12.2013    source источник
comment
Я решил это, используя двойные кавычки. Вот так: ripcheckc ${_args[@]}.   -  person Nordanfors    schedule 05.12.2013


Ответы (3)


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

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

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

array=( "$@" )
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
person devnull    schedule 05.12.2013
comment
Спасибо, это лучший способ избавиться от последнего аргумента. Моя проблема в том, что в $@ есть что-то другое по сравнению с массивом $, который квалифицирует его как допустимый ввод для приложения, которому я его передаю. Я просто не могу понять, что это такое. - person Nordanfors; 05.12.2013
comment
@user1047256 user1047256 Попробуйте передать ${array[@]} в свое приложение. - person devnull; 05.12.2013
comment
Я попробовал то, что вы предложили, но все равно не пошел. К вашему сведению, я сменил ник на Норданфорс. :-) - person Nordanfors; 05.12.2013
comment
@Nordanfors Как иначе передать параметры в ваше приложение? (Не могли бы вы обновить вопрос с информацией?) - person devnull; 05.12.2013
comment
Ваша помощь очень ценится. Не хватало только двойных кавычек вокруг массива, чтобы приложение могло его обработать. Спасибо! - person Nordanfors; 05.12.2013
comment
@Nordanfors Всегда цитирует переменные. - person devnull; 05.12.2013
comment
Следует принять следующий ответ, а не этот. Он имеет тройное количество голосов. - person Noumenon; 06.12.2018
comment
@Noumenon: Bienvenue StackOverflow. Принятый ответ, который со временем становится жалкой бесполезностью, является распространенным случаем, превращая эту функцию StackOverflow в анти-шаблон в дизайне UX. Развивающаяся демократическая мудрость толпы >>>> недемократическое и быстро устаревающее решение одного человека. - person Cecil Curry; 31.12.2018
comment
У этого подхода есть преимущество: операция извлечения становится O(1), так что вы можете поместить ее в цикл. Выделение массива по-прежнему O (n) и медленнее, чем использование подмассива, но это имеет свои преимущества. - person phicr; 08.09.2020

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

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

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


Как это работает:

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

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

person starfry    schedule 02.10.2014
comment
Просто и элегантно: мне это нравится. Я использовал вариант предложения @chepner ниже, чтобы удалить первые два аргумента, чтобы правильно создать подпроцесс: spawnProc ${@:3:$#}. По общему признанию загадочный, но это из-за корней BASH. Это элегантно, хотя и просто. - person Andrew Falanga; 24.02.2017
comment
Могу я запросить постановку этой штуки? - person Steven Lu; 06.12.2017
comment
@StevenLu Я изменил ответ, чтобы дать вам объяснение. Я надеюсь, что это помогает. - person starfry; 06.12.2017
comment
Это идеально! - person Steven Lu; 06.12.2017

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

"${@:0:$#}"

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

Обновление: это работает только из-за ошибки (исправленной не позднее версии 4.1.2) при обработке $@. Работает в версии 3.2.

person chepner    schedule 05.12.2013
comment
Код "${@:1:${#}-1}" - это именно то, что делает полный список аргументов, как в $@, без последнего. - person uvsmtid; 14.03.2015
comment
Правильно. Схематичная часть использует 0 в качестве первого аргумента, чтобы избежать вычитания 1 из второго. - person chepner; 14.03.2015
comment
На самом деле, индекс 0 включает не аргумент - путь к исполняемому скрипту (значение, автоматически предоставляемое оболочкой). Вы не избегаете вычитания 1 - последний аргумент все еще включен, и вы должны вычесть 1. Использование 0 просто добавляет еще одно (вероятно, не обязательное) значение в список. - person uvsmtid; 14.03.2015
comment
Похоже, это работало в bash 3.2 из-за ошибки, которая впоследствии была исправлена. - person chepner; 14.03.2015