Как запустить команду sudo в Emacs?

Я пытаюсь создать сочетания клавиш для некоторых обычно используемых команд sudo shell (например, C-c s run (shell-command "sudo /etc/init.d/apache2 restart")).

Я попытался использовать прямолинейный вызов командной оболочки, как указано выше, но он просто выводит следующее в буфер *Shell Command Output*:

[sudo] password for Inaimathi:
Sorry, try again.
[sudo] password for Inaimathi:
Sorry, try again.
[sudo] password for Inaimathi:
Sorry, try again.
sudo: 3 incorrect password attempts

На самом деле он не запрашивает пароль. Я не хочу запускать Emacs с помощью sudo emacs, но я думаю, что опция, если ничего не будет работать.

Идеальное решение было бы функцией из Emacs (в отличие от OS jiggery-pokery, чтобы изменить поведение оболочки или команды sudo). Что-то вроде (sudo-shell-command "dostuff"), или (with-password-prompt (shell-command "sudo dostuff")).

Ответы

Ответ 1

Как насчет:

(shell-command (concat "echo " (shell-quote-argument (read-passwd "Password? "))
                       " | sudo -S your_command_here"))

Ответ 2

Я часто вызываю команды из Emacs, например aptitude update. scottfrazer решение может быть не таким полезным. Синхронные команды заставляют меня ждать долгое время, и если вы выполняете неподдерживаемую программу (например, aptitude, которая использует ncurses), вы повесите Emacs (C-g не поможет), а загрузка процессора будет на 100%. Переход на async-shell-command разрешает это.

Но это также вводит новую проблему. Если ваша команда не удалась, ваш пароль окажется в буфере *Messages*:

echo PASSWORD | sudo -S aptitude: exited abnormally with code 1.

Вот почему я предлагаю следующее решение:

(defun sudo-shell-command (command)
  (interactive "MShell command (root): ")
  (with-temp-buffer
    (cd "/sudo::/")
    (async-shell-command command)))

Здесь "M" в interactive запрашивает имя программы в минибуфере, with-temp-buffer создает буфер sham, в котором мы меняем каталог на /sudo::/, чтобы использовать TRAMP для приглашения sudo.

Это решение Дэвида Каструп из команда sudo с приглашением пароля минибуфера @gnu.emacs.help.

Обратите внимание, что вы все равно не должны вызывать aptitude напрямую, иначе подпроцесс будет там навсегда, пока вы не отправите sudo pkill aptitude.

Читайте на shells и processes в руководстве.

Ответ 3

Если вы используете emacs22 или более позднюю версию, вы можете просто запустить оболочку из emacs и запустить там команду sudo. Он автоматически выведет вас в окно минибуфера для вашего пароля:

M-x shell
sudo whoami

Это нужно просто попросить пароль внизу в нижней части экрана (без отображения).

Ответ 4

Обходной путь (а не решение emacs):

Настройте пару ключей ssh, чтобы не требовался пароль.

Процедура:

  • запустите ssh-keygen, чтобы сгенерировать пару ключей. Дайте им полезное имя, чтобы они были отсортированы из всех остальных, которые вы сделаете, когда сможете воспользоваться этим.
  • Скопируйте общедоступный файл $HOME/.ssh для учетной записи получателя.
  • Сохраняйте личный адрес в $HOME/.ssh отправляющей учетной записи (вы можете скопировать его на несколько отправляющих учетных записей, но может быть лучше сделать отдельную пару ключей для каждой входящей машины)
  • изменить $HOME/.ssh/config на отправляющей машине, чтобы сообщить ssh, какой ключ использовать
  • Profit

Ответ 5

sudo пытается открыть терминал (tty), чтобы прочитать пароль. Процесс emacs может не иметь управляющего терминала. sudo -S сообщает ему использовать стандартный ввод для пароля, который должен поступать от emacs.

Ответ 6

РЕДАКТИРОВАТЬ: ответ Скотта, который выше, намного предпочтительнее этого взлома. Используйте это.

Возможное решение:

Я выяснил, что настройка утилиты для запроса по умолчанию, разрешающей эту проблему, решает эту проблему.

Мне нужно было добавить Defaults:ALL askpass=/usr/lib/openssh/gnome-ssh-askpass в мой /etc/sudoers файл (используя sudo visudo, очевидно).

Eval-ing (shell-command "sudo /etc/init.d/apache2 restart") теперь запрашивает у меня пароль вместо попыток угадать его безуспешно.

Я не принимаю этот ответ, если не станет ясно, что лучшего решения нет; в идеале я хотел бы что-то, что решает проблему внутри Emacs, вместо того, чтобы требовать, чтобы вы ткнулись в свой каталог /etc.