Обработка функции `zsh` с помощью утилиты, которая распознает только команды

Я знаю, что это уже решено для OP, но для всех, кто наткнулся на этот вопрос, это, похоже, проблема только для версии 10.11 El Capitan. Я пробовал и смог удалить файлы с этим символом в OS X 10.4 Tiger и OS X 10.10 Yosemite, поэтому он, скорее всего, работает с другими.

6
03.06.2017, 16:48
2 ответа

Лучший способ сделать это — просто поместить вашу функцию в файл сценария и вызвать сценарий как таковой:

caffeinate myfunction.sh

Содержимое myfunction.sh:

#!/bin/bash
sleep 2

убедитесь, что файл сценария исполняемый файл, иначе он выдаст вам ошибку разрешения:

chmod +x myfunction.sh
0
27.01.2020, 20:30

caffeinate ожидает выполнения команды в новом процессе.

Чтобы интерпретировать функцию zsh, вам нужна команда zsh.

И вам нужно будет передать ей определение этой функции (, а также других функций, которые могут понадобиться ), например, с помощью:

mysleep() {
  sleep 2
}
caffeinate zsh -c "$(functions mysleep);mysleep"

functions mysleepсбрасывает определение функции mysleep, которую мы передаем этой новой функции zshдля интерпретации перед вызовом функции, так что zsh, вызванная caffeinate, заканчивается интерпретацией:

mysleep() {
  sleep 2
};mysleep

Если сравнить с bash:

mysleep() {
  sleep 2
}
export -f mysleep
caffeinate bash -c "mysleep"

(, что на 2 символа короче, чем ), bashподойдет:

execve("/path/to/caffeinate",
  ["caffeinate", "bash", "-c", "mysleep"],
  ["BASH_FUNC_mysleep%%=() {  sleep 2\n}", rest-of-environment])

В то время как с zshмы получаем:

execve("/path/to/caffeinate",
  ["caffeinate", "zsh", "-c", "mysleep () {\n\tsleep 2\n};mysleep"],
  [rest-of-environment])

Я вижу несколько преимуществ последнего подхода:

  • у нас есть полный контроль :мы знаем, как мы передаем определение функции, как она используется. Здесь меньше возможностей для неприятных вещей вроде контузии.
  • поскольку имя переменной среды bash, которая содержит определение функции, содержит %символов (, и даже если это не так, подумайте о sudo, например ), мы не гарантируем, что caffeinateраспространит его на выполняемую команду bash.
  • если она распространяется, поскольку определение функции хранится в envp[] вместо argv[], это означает, что она загрязняет среду каждой другой команды, выполняемой в этой среде (, включая sleep, например, в этом примере ).
  • (minor )несмотря на то, что шелл-код bashкороче, в execve()передается больше данных, что вносит больший вклад в ограничение E2BIG для этого системного вызова.

Если вы хотите использовать среду, вы все равно можете:

FUNCS=$(functions mysleep) caffeinate zsh -c '
  eval "$FUNCS";mysleep'

В случае caffeinateздесь нам нужно только, чтобы caffeinateвыполнялся во время работы функции, не обязательно, чтобы он запускал функцию, мы можем использовать другие подходы, такие как:

mysleep | caffeinate cat

catбудет работать до тех пор, пока работает mysleep.mysleepпо-прежнему будет выполняться в отдельном процессе, и это влияет на стандартный вывод mysleep.

mysleep 3> {fd}>(caffeinate cat)

решит обе проблемы.

Как и выше, это создает канал между mysleepи cat. Но конец канала для записи теперь находится на вновь выделенном файловом дескрипторе выше 10 (, хранящемся в $fd), в который mysleepобычно не записывается. Таким образом, catничего не будет читать, но дождется конца -файла -в канале, что произойдет только тогда, когдаmysleep(и все дочерние процессы, наследующие этот fd ), завершатся.

1
27.01.2020, 20:30

Теги

Похожие вопросы