Utilisez .bashrc sans casser sftp

20

Mon problème est que je dois définir quelques variables et produire quelques lignes chaque fois que je me connecte au shell ssh, et en même temps, je dois pouvoir utiliser sftp pour tarnfer des fichiers via Filezilla.

Maintenant, conformément à la FAQ openssh à http://www.openssh.org/faq.html , si vos scripts de démarrage font écho à n'importe quel type de sortie, cela gâche avec sftp. Il retarde donc indéfiniment, ou génère une erreur avec une "Connexion fermée par le serveur avec le code de sortie 128".

J'ai essayé des solutions comme déplacer .bashrc vers .bash_profile, ou utiliser le code suivant dans .bashrc:

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

Et:

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

Cependant, rien ne fonctionne. Mon terminal shell est bash, et je me connecte à sftp avec filezilla.

Joel G Mathew
la source

Réponses:

23

Essayez plutôt de le faire

if [ "$SSH_TTY" ]
then
   source .bashc_real
fi
Mike
la source
17

La réponse de Mike fonctionnera probablement. Mais il vaut la peine de souligner que vous pouvez accomplir cela en sélectionnant soigneusement les fichiers de démarrage dans lesquels placer les informations détaillées. À partir de la page de manuel bash:

Lorsque bash est invoqué en tant que shell de connexion interactif, ou en tant que shell non interactif avec l'option --login, il lit et exécute d'abord les commandes du fichier / etc / profile, si ce fichier existe. Après avoir lu ce fichier, il recherche ~ / .bash_profile, ~ / .bash_login et ~ / .profile, dans cet ordre, et lit et exécute les commandes à partir du premier qui existe et est lisible. L'option --noprofile peut être utilisée lorsque le shell est démarré pour inhiber ce comportement.

Lorsqu'un shell interactif qui n'est pas un shell de connexion est démarré, bash lit et exécute des commandes à partir de ~ / .bashrc, si ce fichier existe. Cela peut être inhibé en utilisant l'option --norc. L'option --rcfile file obligera bash à lire et exécuter des commandes à partir du fichier au lieu de ~ / .bashrc.

Les outils sftp / scp démarrent un shell interactif sans connexion, donc .bashrc sera fourni. De nombreuses distributions source .bashrc à partir de .bash_profile ou vice versa, donc cela peut devenir déroutant. Une bonne astuce pour tester la propreté de votre environnement de connexion consiste à utiliser ssh avec une commande, qui simule la même manière que scp / sftp connect. Par exemple: ssh myhost /bin/truevous montrera exactement ce que scp / sftp voit lorsqu'il se connecte.

Une démo simple:

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$

Le premier test provoquera la rupture de scp / sftp / rsync etc. La deuxième version fonctionnera très bien.

Insyte
la source
Je ne suis pas d'accord que "les outils sftp / scp démarrent un shell interactif sans connexion" car nous ne pouvons pas vraiment interagir avec le shell. Mais je ne comprends pas pourquoi .bashrcserait source pour scpou ssh host command.
pynexj
2
Le terme "interactif" n'est pas subjectif. C'est un terme utilisé par bash pour décrire l'un de ses modes de démarrage. C'est un fait que sftp / scp lance un "shell interactif sans connexion". N'hésitez pas à discuter avec les développeurs pour savoir si le sourcing .bashrc n'est pas approprié dans ce cas; Je te dis juste ce que ça fait.
Insyte
2
Bashinvoqué par scpou ssh host commandest en effet non interactif . Je viens de trouver ceci dans le manuel bash: "Bash tente de déterminer quand il est exécuté avec son entrée standard connectée à une connexion réseau , comme lorsqu'il est exécuté par le démon shell distant, généralement rshd, ou le démon shell sécurisé sshd . Si bash détermine il est exécuté de cette façon, il lit et exécute les commandes de ~/.bashrc, si ce fichier existe et est lisible. " Voici l' histoire intéressante .
pynexj
1
Voir également la section Coquilles non interactives non connectées à distance dans cette page wiki .
pynexj
3

Si vous utilisez csh:

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

Et si c'est bash:

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

ou en utilisant des expressions régulières bash:

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

Ces lignes doivent précéder les lignes où vous sortez / faites écho à quelque chose en arrière.

user163384
la source
Bonjour, pourriez-vous expliquer le code, s'il vous plaît. Je sais que $? est le niveau de retour de la commande précédente. Cependant, je ne comprends pas $? Prompt et $ -. Ou est-ce que csh est spécifique?
Joel G Mathew
1
@Droidzone: $?varen cshretourne 1 si varest défini et 0 sinon. $-in bashaurait le caractère idans sa valeur si le shell est interactif.
pynexj
Devrait mettre à jour la réponse pour expliquer $ - est une variable spéciale des options du shell. voir stackoverflow.com/questions/5163144/…
maninvan
1

La solution de Mike a également fonctionné pour moi. Mais comme mon shell par défaut est TCSH, j'ai dû modifier légèrement le correctif comme suit (en .tcshrc):

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

Je pensais juste que je partagerais pour le bénéfice de tous.

Vijay Padiyar
la source
0

J'aime mieux certaines des autres solutions mentionnées ici, mais j'ai pensé jeter la solution que j'utilise actuellement sur mes machines virtuelles bash et csh pour empêcher les déconnexions SFTP en raison des commandes d'écho dans mes scripts de démarrage, juste au cas où quelqu'un trouverait les informations utiles .

En 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

Dans 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"

C'est un peu brutal, mais ça marche.

Bob Noonan
la source
J'ai essayé d'utiliser le code ["$ SSH_TTY"] ci-dessus et j'ai constaté qu'il ne fonctionnait que pour des programmes clients simples comme putty. Lorsque j'utilise NoMachine, il ne fournit aucune sortie. C'est pourquoi j'ai dû inclure "xterm-256color" dans le code ci-dessus.
Bob Noonan
Il est intéressant de noter que l'utilisation de "si ($? SSH_TTY) alors" ne fonctionnait pas non plus pour ma machine virtuelle csh. J'ai vérifié et aucune variable d'environnement SSH_TTY n'est définie. Donc, mon code ci-dessus peut être utile à d'autres qui ont une situation similaire.
Bob Noonan
0

Voici les premières lignes de mon .bashrcfichier (par défaut) :

# ~/.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

La vérification d'une session interactive évite de gâcher SCP, SFTP ou le ssh remote-host commandmode.

Sans cela, si votre fichier .bashrcutilise echoou d'autres éléments d'impression sur stdout, vous pouvez obtenir ce type d'erreurs:

  • SFTP: Received message too long 168435779
  • SCP: protocol error: unexpected <newline>
Totor
la source