Вы звоните main
функция без аргумента. Так $#
в основной функции всегда 0.
Каждый функциональный экземпляр имеет свои собственные аргументы. (“Экземпляр” означает, что, если функция запускается многократно (через рекурсивные вызовы), каждый вызов имеет свои собственные аргументы.) Позиционные параметры $1
, $2
, и т.д., а также связанные параметры $#
, $*
и $@
обратитесь к аргументам, переданным в вызове функции. Например, если Вы звоните main foo bar
затем в main
функционируйте значение $1
будет foo
, значение $#
будет 2 и так далее.
Если Вы хотите передать аргументы сценария к функции, использовать "$@"
. Эта конструкция расширяется до списка аргументов, переданных сценарию (или функции, если названо в функции). Обратите внимание, что в отличие от того, что обычно происходит с двойными кавычками, параметры передаются отдельно, "$@"
список строк и ни одной строки. Двойные кавычки необходимы, иначе параметры не передаются, как всего лишь рассматривается как разделенный от пробела список шаблонов имени файла.
function main {
if (( $# < 1 )); then
usage
fi
echo "good"
}
main "$@"
Я думаю, что вы неправильно интерпретируете происходящее. Когда вы это делаете:
cmd1 && cmd2
оболочка запускает cmd1
в дочернем процессе, ждет этого процесса, а затем запускает cmd2
, если cmd1
выходит со статусом нулевого выхода.
Если нажать Ctrl+Z, ожидание вернется, оболочка установит $?
на 148, например (128 + SIGTSTP), а оценка остального произойдет в этот момент , поэтому cmd2
будет не выполнена. И cmd1
становится фоновым заданием.
Если бы вы набрали:
cmd1 || cmd2
или:
cmd1; cmd2
cmd2
была бы выполнена на Ctrl-Z и вам пришлось бы подождать, пока она завершится, чтобы получить следующую подсказку (где вы можете fg
или bg
ваше фоновое задание).
В zsh
, когда вы нажимаете Ctrl-Z в:
{cmd1 && cmd2 && cmd3}
Это приостанавливает работу всей группы (и перемещает ее в подоболочку). Однако, при возобновлении, команда приостановления, когда она заканчивается, установит $?
на 20, независимо от статуса выхода, и я не думаю, что есть способ обойти это, так что в конечном итоге вы повторите то же самое (хотя в {cmd1 || cmd2}
cmd2 будет выполнена после завершения команды, а не прямо на Ctrl-Z)).
Похоже на приостановку работающего в настоящее время компонента с gdb -p
доказывает изящную паузу, в отличие от kill -STOP
.
Таким образом, если вы знаете, что команда2
выполняется в данный момент, вы можете сделать:
gdb -p $(pgrep -f 'command2')
с другого терминала, чтобы приостановить, а затем выйти или продолжить GDB, чтобы возобновить работу.
Вы можете приостановить родительскую оболочку - интерактивную оболочку, в которой вы запускаете команды в:
Распечатать PID перед запуском команд, (или найти pid позже, см. ниже):
$ echo $$
1234
С другого терминала вы можете остановить весь список команд, приостановив интерактивную оболочку - список состоит из дочерних процессов интерактивной оболочки:
$ kill -STOP 1234
И продолжить список команд с:
$ kill -CONT 1234
Так как это важная часть вашего случая использования, что не требуется никаких приготовлений (например, echo $$
) перед запуском списка команд, вот как вы получите PID оболочки, которую вы хотите остановить, когда список уже запущен на переднем плане.
Идея заключается в том, чтобы найти PID родительского процесса любой из команд в списке:
Сначала мы используем pgrep
, чтобы найти PID текущей выполняемой команды. Поиска PID любой из них достаточно, так как одновременно выполняется только одна:
$ pgrep 'command1|command2|command3'
Если команда1
и т.д. на самом деле не является именем команды процесса - т.е. первым словом командной строки - нужно добавить опцию -f
(и использовать -a
для экспериментов, чтобы увидеть больше, чем просто PID):
$ pgrep -f 'command1|command2|command3'
Затем мы используем ps
, чтобы найти родительский PID команды:
$ ps -o ppid=
Комбинированный, мы получаем PID оболочки, чтобы приостановить так:
$ pid=$(ps -o ppid= $(pgrep 'command1|command2|command3'))
Всего:
$ kill -STOP $(ps -o ppid= $(pgrep 'command1|command2|command3'))
$ kill -CONT $(ps -o ppid= $(pgrep 'command1|command2|command3'))