SSH経由でコマンドを実行すると、.profileに変数がありません。

SSH経由でコマンドを実行すると、.profileに変数がありません。

.NETを介してリモートコンピュータでスクリプトの1つを実行しようsshとすると、奇妙な動作が発生します。

$PATH私の.profileにスクリプトディレクトリパスを追加しました。ただし、実行すると、ssh kalle@Raspi foo「コマンドが見つかりません」というメッセージが表示されます。

ssh kalle@Raspi 'echo $PATH'デフォルト値が与えられ、.profileで設定してエクスポートされた変数を使用すると、出力は空です。

.profileに1を入れたecho fooので、当然印刷されました。その後、最初の行を入力すると、set -vx行は奇妙な順序で印刷されます。たとえば、「+echo foo」の前に「foo」が印刷されます。

何が起こっているのかを理解できる人はいますか?

編集する:

これにより、ssh kalle@Raspi 'bash -lc "echo \$PATH"'フルパスが得られます。

編集2:

混乱させて申し訳ありません。リモートスクリプトを実行しようとすると非常に疲れていました。

使ってみた後、bash -lcコマンドだけ使っても動作しませんでしたが、バックスラッシュが抜けましたね!したがって、ssh kalle@Raspi 'bash -lc "echo $PATH"'通常のようにコマンド文字列を別のコマンドに提供すると、シェルはそのコマンド文字列に対してさまざまな拡張を実行します。

したがって、引用符を削除した後、bash -lc "echo $PATH"それを単一のパラメータとしてssh渡し、シェルがパラメータ置換を実行するリモートシステムで実行します。つまり、$PATHデフォルトパスに置き換えます。今後に渡され、bash -lc後者を無駄にします。

だから愚かに使用しているという事実bash -lcを忘れてしまった。ssh kalle@Raspi foo.profileecho.profile

本当に恥ずかしいことです。この質問を書くときにバックスラッシュを使って変数を保護する必要があることは私には全く当然だと感じたので疲れていたでしょう。しかし、私は今気付いたことをまだ理解していません。

したがって、この動作は非常に明白で絶対に正常ですが、問題はまだ存在します。

bash -lc状況によっては、引用とエスケープが面倒な解決策を使用することも、. .profile実際のコマンドの前に置くこともできます。

よりエレガントなソリューションを知っている人はいますか?サーバーで調整できるものはありますかssh kalle@Raspi foo

答え1

@ilkkachuのおかげで解決策を見つけました。

変数の内容を.profile.profile

その後、「インタラクティブで実行されていない場合は何もしません」部分を.bashrc次のように修正しました。

case $- in
    *i*) ;;
      *)
        # Not running interactively.
        # Check if we are the server of an SSH connection without a PTY.
        # If so, sshd is about to execute a command issued by some client,
        # in which case this script has been invoked directly by sshd, not
        # by .profile, so we need to set vars that are normally set in .profile
        # and that are important for my scripts (like $PATH) here before returning.
        # This way, I can call my scripts just via ‘ssh kalle@Raspi foo’ without
        # using ‘bash -lc’.
        #
        # References:
        # https://www.gnu.org/software/bash/manual/html_node/Bash-Startup-Files.html
        # https://man.openbsd.org/ssh#ENVIRONMENT

        [[ $SSH_CONNECTION && -z $SSH_TTY ]] && . $HOME/scripts/bashrc-include/set-vars.sh
        return;;
esac

編集する:

まったく重要ではないわけではありません。効果があり、副作用がないことが証明されています。

echoandの前にはesを、topの後にはesを付けました。.profile.bashrcset-vars.shechocase ... in ... esac

私はすべての機械で同じものを使用することに言及するべきです.profile.bashrc

それではテストしてみましょう。

この記事を書いているコンピュータで端末を開くと、次の結果が表示されます。

.profile: Started.
set-vars.sh: Setting vars.
.bashrc: Started.
.bashrc: Interactive shell, proceeding.

RaspiにSSHを接続すると、同じ結果が表示されます。

発行するとssh kalle@Raspi 'echo $PATH'次のようになります。

.bashrc: Started.
set-vars.sh: Setting vars.

そして正しいです$PATH

編集2:

メッセージを開いて閉じるための小さなスクリプト:

#!/bin/bash

# Author: derkallevombau
# Created 2023-04-07 12:58:48

if [[ $1 =~ ^on|1|true$ ]]; then
    sedScript='"s/^#([\t ]*echo $(basename $f):.*)/\1/"'
elif [[ $1 =~ ^off|0|false$ ]]; then
    sedScript='"s/^([\t ]*echo $(basename $f):.*)/#\1/"'
else
    cat <<-END
        Unknown argument: '$1'.

        Invocation: bash-startup-messages-set (on|1|true)|(off|0|false)
    END

    exit
fi

for f in ~/.{profile,bashrc} /home/kalle/scripts/bashrc-include/set-vars.sh; do
    eval sed -Ei $sedScript $f
done

関連情報