Ubuntu: как получить PID запущенного процесса

Маленькие "хитрости" bash. На примере перезапуска приложения node.js
#!/bin/bash
# чтобы было легче жить, добавим все нужные пути в переменные
DAEMON="/usr/local/bin/node"
ROOT_DIR="/home/user/project-copy-folder"
# тут на основании базовых путей выставляем пути к файлам PID, 
# логов и скрипта, запускающего само приложение
PIDFILE="$ROOT_DIR/pidfile"
SERVER="$ROOT_DIR/app.js"
LOG_FILE="$ROOT_DIR/app.js.log"

# останавливаемся, обратите внимание на то, как получается и обрабатывается PID
echo -n "Stopping $SERVER: "
kill -9 $(cat $PIDFILE) && echo 'ok stoped' || echo 'error on stop my-funny app'

# чистим логи и убираем старый PID (это опционально)
>$LOG_FILE
>$PIDFILE

# стартуем. тут самое как мне кажется, непонятное — это конструкция echo $! > $PIDFILE
# здесь $! это PID последнего запущенного приложения (читаем ман по bash), с пониманием
# этого нюанса становится понятно все остальное
echo -n "Starting $SERVER: "
`$DAEMON $SERVER > $LOG_FILE & echo $! > $PIDFILE &` && echo 'ok, started' || echo 'error on start my-funny app'
Интересная особенность как мне показалось состоит в том, что если мы выполним например вот такой код
/usr/local/bin/node /home/user_name/project/app.js &
echo $!
То увидим напечатанный PID. А вот если исполнить тоже самое, но через eval
NODE='/usr/local/bin/node'
APP='/home/user_name/project/app.js'
`$NODE $APP &`
echo $!
То не увидим ничего. То есть eval где-то у себя это значение закусывает и нам оно нормально не доезжает. Соответственно решением (скорее всего одним из решений, так как я никакой не специалист по bash), будет получение PID-а прямо внутри этого самого eval-a как показано в первом примере.

Из переменной (правильно называть это переменными??) $$ - можно получить PID текущего скрипта, то есть если вы планируете в нем зависнуть то имеет смысл положить куда-то PID-файл чтобы потом что-то с этим процессом делать. Баш вообще интересная штука, жаль почти не остается времени на глубокие раскопки в этих шаманствах.

Ubuntu: как запустить скрипт от имени другого пользователя

Мне это понадобилось для автоматического подъема сервиса после внештатной перезагрузки сервера.
Как всегда, все просто:
su USER -c '/home/USER/folder/script.sh'
Собственно man su рассказывает всё в примерах.
su man -c catman
# Runs the command catman as user man.  You will be asked for man's password unless your real UID is 0.

su man -c 'catman /usr/share/man /usr/local/man'
# Same as above, but the target command consists of more than a single word and hence is quoted for use 
# with the -c option being passed to the shell.  (Most shells expect the argument to -c to be a single word).

su -l foo
# Simulate a login for user foo.

su - foo
# Same as above.

Express.js error handing

Поднобные объяснения на английском можно почитать вот тут. Суть в том, что в express.js метод передачи ошибок несколько отличается. Лично мне пока не очень понятно почему так, но инженер который собственно и разрабатывает express.js выбрал такой путь. Наверное с точки зрения идеологии node.js и асинхронного программирования вообще - это правильно (именно передавать ошибки по цепочке, а не ловить их), но мне на данный момент кажется что это несколько кривовато. Если пойму со временем в чем смысл именно такого подхода, то допишу подробнее или исправлю запись.

Обычно в node.js exception-ы ловятся по-человечески, то есть вот так
app.get('/home', function(req, res){
    // ошибка
    throw new Error('error text msg');
});
В случае с express.js схема работы такая
app.get('/home', function(req, res, next){
    // ошибка
    next(new Error('error text msg'));
});
Причем интересно, что в таком простом примере в express.js вполне сработает и первый вариант, но вот пример ниже уже работать не будет. Насколько я понял дело в том что выкинули общий хэндлер ошибок app.error(function(err,...)). Честно говоря причин такого решения я пока не нашел.
app.get('/home', function(req, res, next){
  db.getRow("SELECT * FROM ...", function(err, row){
    throw new Error('error text msg');
  });
});
В этом случае ошибка просвистит мимо и приложение завалится. Православный путь на данный момент — таскать все ошибки по цепочке вручную. Писанины к сожалению получается несколько больше, но вполне вписывается в предусмотренную схему. Неудобно, но пока найдется что-то повеселее - это рабочее решение. Надо будет собраться написать Tj на эту тему.

Как управлять ошибками в express.js сейчас.
./app.js
app.configure(function(){
  //.. здесь вся остальная необходимая конфигурация

  // error 500
  app.use(function(err, req, res, next) {
    res.status(500).render('err500', {
      title: 'ouch.. 500 error',
      err: err
    });
  });
});

// "контроллер" блога
var blog = require('./routes/blog');
// роут на конкретную операцию
app.get('/post/:post_id', blog.blogPost);
./routes/blog
// ... остальное содержимое контроллера
exports.blogPost = function(req, res, next)
{
  // .. проверки что-то ещё
  db.getRow("SEL33ECT b.* \
    FROM blog b \
    WHERE blog_id=?",
    [
      post_id
    ], function(err, post){
      // ловим ошибку
      if (err) {
        return next(err);
      }

      // тут что-то дальше происходит
      // ...
  });
};

Как в mac os переназначить клавиши End и Home

Наверное яростные адепты macos забросают меня камнями, но я так и не понял в чем кайф вот такого пользования Home\End (дефолтное назначение в macos) и решил вернуться к PC-шному варианту.

Создаем файл ~/Library/KeyBindings/DefaultKeyBinding.dict с содержимым приведенным ниже
{
    /* home */
    "\UF729"  = "moveToBeginningOfLine:";
    "$\UF729" = "moveToBeginningOfLineAndModifySelection:";

    /* end */
    "\UF72B"  = "moveToEndOfLine:";
    "$\UF72B" = "moveToEndOfLineAndModifySelection:";
}
Для того чтобы новые бинды заработали мне пришлось завершить сеанс и зайти снова. Перезагрузка не потребовалась. Найдено гуглением, тестировано на 10.8.3

Как восстановить пароль в Ubuntu

Наконец это случилось и со мной. Я умудрился забыть пароль от ноута.
Слава зайцам восстановить доступ в убунте довольно просто. Я раза с третьего нагуглил нормальное решение.
На всякий случай здесь тоже напишу.
  • При загрузке системы удерживая Shift попадаем в меню Grub, из него входим в режим восстановления (он же "recovery mode", через "доп параметры" в 12.10 на других могут быть различия)
  • Далее при загрузке появится меню режима восстановления, в нем выбираем строку root (в 12.10 "root - Drop to root shell prompt")
  • Откроется рутовая консоль, теперь чтобы изменить пароль надо перемонтировать файловую систему для записи, выполняем команду
    mount -rw -o remount /
  • Если забыли ещё и логин то можно выполнить
    cat /etc/passwd
    В появившемся выводе поискать знакомые имена пользователей :)
  • Теперь собственно меняем пароль
    passwd userName
    Где UserName - логин пользователя, для которого меняется пароль.
  • Теперь перезагружаемся
    shutdown -r now
  • Profit!