Используйте .bashrc, не нарушая sftp

20

Моя проблема в том, что мне нужно установить несколько переменных и выводить несколько строк каждый раз, когда я вхожу в оболочку ssh, и в то же время я должен иметь возможность использовать sftp для передачи файлов через Filezilla.

Теперь, в соответствии с часто задаваемыми вопросами openssh по адресу http://www.openssh.org/faq.html , если ваши скрипты запуска выводят какой-либо вывод, он ошибается с sftp. Таким образом, он либо задерживается на неопределенное время, либо выдает ошибки с «Соединением, закрытым сервером с кодом выхода 128».

Я пробовал такие решения, как перемещение .bashrc в .bash_profile или использование следующего кода в .bashrc:

if [ "$TERM" != "dumb" ]
then
   source .bashc_real
fi

И:

if [ "$TERM" = "xterm" ]
then
   source .bashc_real
fi

Однако ничего не работает. Мой терминал оболочки bash, и я подключаюсь к sftp с помощью filezilla.

Джоэл Г Мэтью
источник

Ответы:

23

Попробуйте сделать это вместо

if [ "$SSH_TTY" ]
then
   source .bashc_real
fi
Майк
источник
17

Вероятно, ответ Майка сработает. Но стоит отметить, что вы можете выполнить это, тщательно выбирая, какие файлы запуска добавить подробные данные. На странице руководства bash:

Когда bash вызывается как интерактивная оболочка входа в систему или как неинтерактивная оболочка с параметром --login, она сначала читает и выполняет команды из файла / etc / profile, если этот файл существует. После прочтения этого файла он ищет ~ / .bash_profile, ~ / .bash_login и ~ / .profile в указанном порядке, а также читает и выполняет команды из первой, которая существует и доступна для чтения. Опция --noprofile может использоваться, когда оболочка запущена, чтобы запретить это поведение.

Когда запускается интерактивная оболочка, которая не является оболочкой входа в систему, bash читает и выполняет команды из ~ / .bashrc, если этот файл существует. Это может быть запрещено с помощью параметра --norc. Опция --rcfile file заставит bash читать и выполнять команды из файла вместо ~ / .bashrc.

Инструменты sftp / scp запускают интерактивную оболочку без входа в систему, поэтому .bashrc будет получен. Многие дистрибутивы исходят из .bashrc из .bash_profile или наоборот, поэтому это может сбить с толку. Хорошим трюком для проверки чистоты среды входа в систему является использование команды ssh, которая имитирует подключение scp / sftp. Например: ssh myhost /bin/trueпокажет вам, что именно видит scp / sftp при подключении.

Простая демонстрация:

insyte@mazer:~$ echo "echo Hello from .profile" > .profile
insyte@mazer:~$ echo "echo Hello from .bashrc" > .bashrc

sazerac:~ insyte$ ssh mazer /bin/true
Hello from .bashrc
sazerac:~ insyte$

insyte@mazer:~$ rm .bashrc

sazerac:~ insyte$ ssh mazer /bin/true
sazerac:~ insyte$

Первый тест приведет к сбою scp / sftp / rsync и т. Д. Вторая версия будет работать просто отлично.

Insyte
источник
Я не согласен с тем, что «инструменты sftp / scp запускают интерактивную оболочку без входа в систему», поскольку мы не можем реально взаимодействовать с этой оболочкой. Но я не понимаю, почему источник .bashrcбудет для scpили ssh host command.
pynexj
2
Термин «интерактивный» не субъективен. Это термин, используемый bash для описания одного из режимов запуска. Фактом является то, что sftp / scp запускает «интерактивную оболочку без авторизации». Не стесняйтесь спорить с разработчиками о том, подходит ли в этом случае источник .bashrc; Я просто говорю вам, что он делает.
Insyte
2
Bashвызывается scpили ssh host commandдействительно не является интерактивным . Я только что нашел это в руководстве bash: «Bash пытается определить, когда он запускается со своим стандартным входом, подключенным к сетевому соединению , как при выполнении демоном удаленной оболочки, обычно rshd, или демоном защищенной оболочки sshd . Если bash определяет он запускается таким образом, он читает и выполняет команды ~/.bashrc, если этот файл существует и доступен для чтения ». Вот интересная история .
pynexj
1
Также см. Раздел Удаленные неинтерактивные неинтерактивные оболочки на этой вики-странице .
pynexj
3

Если вы используете csh:

if ($?prompt)
  ... interactive stuff ...

И если это bash:

if [[ $- == *i* ]]; then
  ... interactive stuff ...
fi

или альтернативно используя регулярные выражения bash:

if [[ $- =~ i ]]; then
  ... interactive stuff ...
fi

Эти строки должны предшествовать строкам, в которых вы выводите / выводите что-то обратно.

user163384
источник
Привет, не могли бы вы объяснить код, пожалуйста. Я знаю, что $? это уровень возврата предыдущей команды. Я не понимаю $? Prompt и $ -, хотя. Или специфично для csh?
Джоэл Г Мэтью
1
@Droidzone: $?varin cshвозвращает 1, если varопределено, и 0 в противном случае. $-in bashбы имеет iсимвол в своем значении, если оболочка является интерактивной.
pynexj
Следует обновить ответ, чтобы объяснить $ - это специальная переменная параметров оболочки. см. stackoverflow.com/questions/5163144/…
maninvan
1

Решение Майка сработало и для меня. Но так как моя оболочка по умолчанию - TCSH, мне пришлось немного отредактировать исправление следующим образом (в .tcshrc):

if ( $?SSH_TTY ) then
    exec /bin/bash
endif

Просто думал, что поделюсь всем на пользу.

Виджей Падияр
источник
0

Мне больше нравятся некоторые другие решения, упомянутые здесь, но я подумал, что выброшу решение, которое я сейчас использую на своих виртуальных машинах bash и csh, чтобы предотвратить отключение SFTP из-за команд echo в моих сценариях запуска, на тот случай, если кто-то найдет эту информацию полезной. ,

В BASH:

if [ $TERM == "xterm" ] || [ $TERM == "xterm-256color" ]; then
  echo "Xterm display identified: echo enabled"
  echo_disable="0"
else
  echo_disable="1"
fi

# Use the following for all subsequent echo commands
if [ $echo_disable == 0 ]; then
 echo "Safe to display on Xterm"
fi

В csh:

if ($TERM == "xterm") then
  echo "Xterm display identified: echo enabled"
  set echo_disable = "0"
else
  set echo_disable = "1"
endif

# Use the following for all subsequent echo commands
if !( "$echo_disable" ) echo "Safe to display on Xterm"

Это немного грубая сила, но она работает.

Боб Нунан
источник
Я попытался использовать код ["$ SSH_TTY"] выше и обнаружил, что он работает только для простых клиентских программ, таких как putty. Когда я использую NoMachine, он не дает никакого вывода. Вот почему мне нужно было включить «xterm-256color» в приведенный выше код.
Боб Нунан
Интересно, что использование «if ($? SSH_TTY) then» также не работало на моей csh VM. Я проверил, и переменная окружения SSH_TTY не определена. Так что мой код выше может быть полезен для других, у которых похожая ситуация.
Боб Нунан
0

Вот первые строки моего (по умолчанию) .bashrcфайла:

# ~/.bashrc: executed by bash(1) for non-login shells.
# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
# for examples

# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac

Проверка интерактивного сеанса позволяет избежать путаницы с SCP, SFTP или ssh remote-host command режимом.

Без этого, если ваш файл .bashrcиспользуетecho или печатает что-то другое на stdout, вы можете получить такие ошибки:

  • SFTP: Received message too long 168435779
  • SCP: protocol error: unexpected <newline>
Totor
источник