Рабочий процесс Emacs для редактирования скриптов Bash во время их работы - PullRequest
8 голосов
/ 01 декабря 2011

Bash может дать неожиданные результаты, если кто-либо редактирует скрипт во время его работы .Но часто было бы очень удобно иметь возможность редактировать временную копию скрипта, который я запускаю в оболочке, но перед тем, как снова запустить его, убедитесь, что он вернулся в исходное местоположение.У кого-нибудь есть предложения по рабочему процессу или настройкам Emacs для облегчения этого?

Ответы [ 4 ]

8 голосов
/ 02 декабря 2011

M-x delete-file, нажмите down, чтобы вставить, получите путь к файлу, который вы редактируете, и RET, чтобы удалить файл.Когда вы в следующий раз сохраните свой буфер, это создаст новый файл.Bash продолжит выполнение старого удаленного файла.

Кстати, в большинстве случаев вам даже не нужно предпринимать эту меру предосторожности.Emacs обычно сохраняет во временный файл, а затем переименовывает этот временный файл в правильное имя файла (которое удаляет старый файл, если только он не сохраняется в качестве резервной копии).Emacs перезаписывает файл на месте только в том случае, если обнаруживает, что не может воссоздать файл должным образом: если файл имеет жесткие ссылки или если у вас нет разрешения на запись в каталог.(Я немного упрощаю; подробности в функции basic-save-buffer-2 в files.el.) Пока файл имеет одну запись в каталоге и у вас есть права на запись в каталог, содержащий скрипт, просто нажмите C-x C-s.

7 голосов
/ 19 января 2012

В этом ответе я

  1. дополняю хороший ответ Жиля теорией.
  2. предлагаю улучшение в использовании emacs.
  3. предлагаю альтернативы, чистос помощью сценариев оболочки.

Предупреждение: я не профессиональный программист.

1 Теория

Причина удаления безопасна, но модификация заключается не в том, что в Unixудаленный файл становится недоступным из файловой системы, но процессы, открывшие файл (здесь / bin / bash), все равно могут его прочитать, как объяснено здесь .Дело не в том, что bash делает что-то особенное, например, буферизацию всего файла, а просто читает.(Даже после удаления вы можете восстановить сценарий во время его работы, , как описано здесь . В bash сценарий всегда открывается как 255, /proc/<pid>/fd/255.)

2Решение Emacs

Теперь Emacs;чтобы быть в безопасности, вы можете автоматизировать все;добавьте к before-save-hook функцию, чтобы проверить, является ли это sh-режимом, и удалите автоматически, если скрипт открыт, проверяя с помощью lsof:

(defvar delete-open-sh-flag nil
  "Used by `delete-open-sh.` If nil, deletion didn't happen.
Otherwise, the mode is saved.")

(defun delete-open-sh ()
  (setq delete-open-sh-flag nil)
  (when (and (eq major-mode 'sh-mode)
         (buffer-file-name)
         (file-exists-p (buffer-file-name)))
    (let ((buf (generate-new-buffer " *foo*")))
      (call-process "lsof" nil; infile
            buf ; dest
            nil ; display
            (buffer-file-name))
      (unless (eq 0 (buffer-size buf))
        (setq delete-open-sh-flag (file-modes (buffer-file-name)))
        (delete-file (buffer-file-name)))
      (kill-buffer buf))))

(defun delete-open-sh-after ()
  (when delete-open-sh-flag
    (set-file-modes (buffer-file-name) delete-open-sh-flag)))

(add-hook 'before-save-hook 'delete-open-sh)
(add-hook 'after-save-hook 'delete-open-sh-after)

Но это не идеально.Сохраняет файловый режим, но это все.

3 Чистое решение bash

Или вы можете позволить самому сценарию bash удалить данные.Используйте это:

# Usage: . /path/to/this-script (Always use abs path)

# Restart the caller script itself in a temporary file; this allows
# editing of the caller script file while it's run.
# Temporary file is soon deleted.
#
if [[ ! "`dirname $0`" =~ ^/tmp/.sh-tmp ]]; then
    mkdir -p /tmp/.sh-tmp/
    DIST="/tmp/.sh-tmp/$( basename $0 )"
    install -m 700 "$0" $DIST
    exec $DIST "$@"
else
    rm "$0"
fi

Пример использования: сохраните этот файл в /home/foo/a.sh:

#!/bin/sh
echo "$0 $@"
. /home/foo/the-above-code.sh
echo "Again, $0 $@"

Если вы вызовете вышеуказанный скрипт как ./a.sh 1 2 3, результатэто:

/home/foo/a.sh 1 2 3
/tmp/.sh-tmp/a.sh 1 2 3
Again, /tmp/.sh-tmp/a.sh 1 2 3

Это может быть лучше, но использовать на свой страх и риск.

Также известно, что все в скобках, заключая с exit, делает работу, какобъяснил здесь .

2 голосов
/ 15 сентября 2016

Просто добавьте это решение в качестве простого и понятного способа защиты работающих скриптов BASH от изменения:

#! /bin/bash
{
your_code;
exit;
}
2 голосов
/ 01 декабря 2011

У меня уже была функция для переименования файла текущего буфера.был короткий переход к функции, которая позволяла легко переключаться на временную версию файла и затем снова возвращаться.в основном, если вы запускаете эту функцию при посещении обычного файла "foo.txt", он скопирует файл в новый файл в том же каталоге с именем "tmp.foo.txt".редактировать по желанию.когда будете готовы вернуться назад, запустите функцию еще раз, и она вернет временный файл поверх исходного файла.я использовал префикс "tmp".вместо суффикса, потому что большинство режимов распознавания в emacs основано на суффиксе (вы, вероятно, могли бы сделать что-нибудь более изобразительное, запомнив все режимы буфера и повторно применив ...).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...