Verwenden Sie .bashrc, ohne sftp zu beschädigen


20

Mein Problem ist, dass ich jedes Mal, wenn ich mich bei der ssh-Shell anmelde, ein paar Variablen setzen und ein paar Zeilen ausgeben muss. Gleichzeitig muss ich in der Lage sein, mit sftp Dateien über Filezilla zu tarnsfen.

Wenn Ihre Startskripte nun, wie in den OpenSSH-FAQ unter http://www.openssh.org/faq.html beschrieben , irgendeine Ausgabe wiedergeben, führt dies zu einer Störung von SFTP. Es verzögert sich also entweder auf unbestimmte Zeit oder es treten Fehler mit der Meldung "Die Verbindung wurde vom Server mit dem Beendigungscode 128 geschlossen" auf.

Ich habe Lösungen wie das Verschieben von .bashrc nach .bash_profile oder die Verwendung des folgenden Codes in .bashrc ausprobiert:

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

Und:

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

Es funktioniert jedoch nichts. Mein Shell-Terminal ist bash und ich verbinde mich mit filezilla mit sftp.

Antworten:


23

Versuchen Sie dies stattdessen

if [ "$SSH_TTY" ]
then
   source .bashc_real
fi

17

Mikes Antwort wird wahrscheinlich funktionieren. Es sei jedoch darauf hingewiesen, dass Sie auf diese Weise sorgfältig auswählen können, in welche Startdateien das ausführliche Material eingefügt werden soll.

Wenn bash als interaktive Anmeldeshell oder als nicht interaktive Shell mit der Option --login aufgerufen wird, werden zuerst Befehle aus der Datei / etc / profile gelesen und ausgeführt, sofern diese Datei vorhanden ist. Nach dem Lesen dieser Datei sucht sie in dieser Reihenfolge nach ~ / .bash_profile, ~ / .bash_login und ~ / .profile und liest und führt Befehle von der ersten Datei aus, die vorhanden und lesbar ist. Die Option --noprofile kann verwendet werden, wenn die Shell gestartet wird, um dieses Verhalten zu unterbinden.

Wenn eine interaktive Shell gestartet wird, die keine Anmeldeshell ist, liest bash Befehle von ~ / .bashrc und führt sie aus, sofern diese Datei vorhanden ist. Dies kann mit der Option --norc verhindert werden. Die Option --rcfile file erzwingt, dass Bash anstelle von ~ / .bashrc Befehle aus der Datei liest und ausführt.

Die sftp / scp-Tools starten eine interaktive Shell ohne Anmeldung, sodass .bashrc als Quelle verwendet wird. Viele Distributionen beziehen .bashrc aus .bash_profile oder umgekehrt, so dass es verwirrend werden kann. Ein guter Trick, um die Sauberkeit Ihrer Anmeldeumgebung zu testen, besteht darin, ssh mit einem Befehl einzugeben, der auf dieselbe Weise scp / sftp connect simuliert. Beispiel: ssh myhost /bin/trueZeigt Ihnen genau, was scp / sftp sieht, wenn sie eine Verbindung herstellen.

Eine einfache Demo:

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$

Der erste Test führt zum Abbruch von scp / sftp / rsync usw. Die zweite Version wird gut funktionieren.


Ich stimme nicht zu, dass "die SFTP / SCP-Tools eine interaktive Shell ohne Anmeldung starten ", da wir nicht wirklich mit der Shell interagieren können . Aber ich verstehe nicht, warum .bashrcfür scpoder ssh host command.
Pynexj

2
Der Begriff "interaktiv" ist nicht subjektiv. Dieser Begriff wird von der Bash verwendet, um einen der Startmodi zu beschreiben. Tatsache ist, dass sftp / scp eine "interaktive Nicht-Login-Shell" starten. Zögern Sie nicht, mit den Entwicklern darüber zu streiten, ob in diesem Fall die Beschaffung von .bashrc angemessen ist. Ich sage dir nur, was es tut.
Insyte

2
Bashaufgerufen von scpoder ssh host commandist in der Tat nicht interaktiv . Ich habe dies gerade im bash-Handbuch gefunden: "Bash versucht zu bestimmen, wann es mit seiner Standardeingabe ausgeführt wird, die mit einer Netzwerkverbindung verbunden ist , wie wenn es vom fernen Shell-Daemon ausgeführt wird, normalerweise rshd oder dem sicheren Shell-Daemon sshd . Wenn bash feststellt es wird auf diese Weise ausgeführt, es liest und führt Befehle aus ~/.bashrc, wenn diese Datei existiert und lesbar ist. " Hier ist die interessante Geschichte .
Pynexj

1
Siehe auch den Abschnitt Remote non login non interactive shells auf dieser Wiki-Seite .
Pynexj

3

Wenn Sie csh verwenden:

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

Und wenn es heftig ist:

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

oder alternativ mit bash regulären Ausdrücken:

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

Diese Zeilen sollten vor den Zeilen stehen, in denen Sie etwas zurückgeben / ausgeben.


Hallo, könnten Sie bitte den Code erklären. Ich weiß, dass $? ist die Rückgabeebene des vorherigen Befehls. Ich verstehe $? Prompt und $ - allerdings nicht. Oder ist csh spezifisch?
Joel G Mathew

1
@Droidzone: $?varin dem cshWert 1 zurück , wenn vardefiniert ist , und 0 sonst. $-in bashwould hat das iZeichen in seinem Wert, wenn die Shell interaktiv ist.
Pynexj

Sollte das Update antworten, um zu erklären, dass $ - eine spezielle Variable der Shell-Optionen ist. siehe stackoverflow.com/questions/5163144/…
maninvan

1

Mikes Lösung funktionierte auch für mich. Da meine Standardshell TCSH ist, musste ich das Update wie folgt leicht bearbeiten (in .tcshrc):

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

Ich dachte nur, ich würde zum Wohle aller teilen.


0

Ich mag einige der anderen hier erwähnten Lösungen besser, aber ich dachte, ich verwerfe die Lösung, die ich derzeit auf meinen Bash- und CSH-VMs verwende, um zu verhindern, dass SFTP-Verbindungen aufgrund von Echobefehlen in meinen Startskripten getrennt werden, falls jemand die Informationen hilfreich findet .

In der 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

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

Es ist ein bisschen rohe Gewalt, aber es funktioniert.


Ich habe versucht, den obigen Code ["$ SSH_TTY"] zu verwenden und festgestellt, dass er nur für einfache Client-Programme wie Putty funktioniert. Wenn ich NoMachine benutze, liefert es keine Ausgabe. Aus diesem Grund musste ich "xterm-256color" in den obigen Code einfügen.
Bob Noonan

Interessanterweise funktionierte die Verwendung von "if ($? SSH_TTY) then" auch nicht für meine csh-VM. Ich habe es überprüft und es ist keine SSH_TTY-Umgebungsvariable definiert. Mein Code oben kann daher für andere hilfreich sein, die eine ähnliche Situation haben.
Bob Noonan

0

Hier sind die ersten Zeilen meiner (Standard-) .bashrcDatei:

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

Die Prüfung für eine interaktive Sitzung verhindert, dass SCP, SFTP oder der ssh remote-host commandModus durcheinander gebracht werden.

Andernfalls kann es zu folgenden Fehlern kommen , wenn Ihre Datei stdout .bashrcverwendet echooder wenn andere Dinge auf stdout gedruckt werden:

  • SFTP: Received message too long 168435779
  • SCP: protocol error: unexpected <newline>
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.