Запуск ssh удаленных команд на `bash_history`

SSH позволяет удаленному пользователю выдать некоторую команду без интерактивного входа на сервер, поскольку последняя строка использования ssh указывает:

 usage: ssh [-1246AaCfgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_spec] [-D [bind_address:]port] [-E log_file] [-e escape_char] [-F configfile] [-I pkcs11] [-i identity_file] [-L [bind_address:]port:host:hostport] [-Q protocol_feature] [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port] [-R [bind_address:]port:host:hostport] [-S ctl_path] [-W host:port] [-w local_tun[:remote_tun]] [user@]hostname [command] 

Когда ssh вызывается с помощью удаленной команды, файл .bash_history не обновляется (т. .bash_history Удаленная команда не добавляется в .bash_history ). Мне удалось «имитировать» этот эффект, добавив следующую команду в /etc/ssh/sshd_config :

 ForceCommand if [[ -z $SSH_ORIGINAL_COMMAND ]]; then bash; else printf "$SSH_ORIGINAL_COMMAND\n" >> .bash_history; bash -c "$SSH_ORIGINAL_COMMAND"; fi 

Вышеприведенная команда проверяет, является ли переменная среды $SSH_ORIGINAL_COMMAND пустой:

  • Если это так, удаленная команда не выдается, и мы просто запускаем bash .
  • В противном случае $SSH_ORIGINAL_COMMAND добавляется в .bash_history , и удаленная команда в $SSH_ORIGINAL_COMMAND выполняется.

Он работает так, как ожидалось, но мне нужно немного больше: я хочу, чтобы текущая временная метка была добавлена ​​в .bash_history . С этой целью я добавил следующую команду в /etc/ssh/sshd_config :

 ForceCommand if [[ -z $SSH_ORIGINAL_COMMAND ]]; then bash; else printf "#`date +%s`\n$SSH_ORIGINAL_COMMAND\n" >> .bash_history; bash -c "$SSH_ORIGINAL_COMMAND"; fi 

Но когда я пытаюсь ssh на сервер, я получаю следующую ошибку:

 bash: -c: line 0: unexpected EOF while looking for matching `"' bash: -c: line 1: syntax error: unexpected end of file Connection to 127.0.0.1 closed. 

Если я удаляю # до date +%s , он работает правильно. Но мне нужно, чтобы # был напечатан до отметки времени, так как это правильный формат для файла .bash_history .

A # в sshd_config интерпретируется как начало комментария, и все последующее за ним игнорируется. Хотя (согласно sshd_config(5) ) "" может использоваться для цитирования аргументов, содержащих пробелы, они не цитируют # .

Это также объясняет вашу ошибку. sshd передает только bash :

 if [[ -z $SSH_ORIGINAL_COMMAND ]]; then bash; else printf " 

Второй " не может быть найден, поскольку командная строка заканчивается сразу после первой.

Чтобы предотвратить это поведение, литерал # не должен использоваться:

  • Поскольку printf используется здесь, в любом случае, использование его возможностей для использования символов с обратными слэшами может оказаться полезным. # может быть записано как \x23 (шестнадцатеричный), \43 (восьмеричный), \u23 (Unicode, шестнадцатеричный до 4 шестнадцатеричных цифр) или даже \U23 (Unicode, шестнадцатеричный до 8 шестнадцатеричных цифр). То же самое работает для echo -e . Обратите внимание, что \ должен быть указан, поэтому используйте либо "\43" , '\43' либо \\43 .

  • В тех случаях, когда вам не нужны echo или printf , вы можете получить bash (также работает на zsh ), чтобы выполнить замену, используя $'string' . Например: чтобы сделать touch foo#bar , вы можете написать touch $'foo\x23bar' . Если значение меньше максимального количества разрешенных цифр (3 для восьмеричных, 2 для шестнадцатеричных и 4 или 8 соответственно для Unicode), вы должны использовать начальные нули, чтобы избежать неправильных интерпретаций. Например: $'foo\u23bar' оценивается как foo⎺r а $'foo\u0023bar' дает ожидаемую foo#bar .

  • Избегайте использовать # (буквально или иначе) все вместе, поместив все функциональные возможности в скрипт, а затем просто установите ForceCommand /path/to/script в свою конфигурацию.

Второй вариант также позволяет отказаться от printf , используя формат date более широко. Вместо

 printf "\x23`date +%s`\n$SSH_ORIGINAL_COMMAND\n" >> .bash_history 

Ты можешь написать

 date $'+\x23%s'"${SSH_ORIGINAL_COMMAND//%/%%}" >> .bash_history