通过 ssh 执行命令时 .profile 中没有变量

通过 ssh 执行命令时 .profile 中没有变量

当我尝试通过ssh.在远程计算机上执行我的脚本之一时,我遇到了奇怪的行为。

我将脚本目录的路径添加到$PATH我的 .profile 中。但是当我运行时ssh kalle@Raspi foo,我得到“命令未找到”。

ssh kalle@Raspi 'echo $PATH'给出默认值,并且使用我在 .profile 中设置和导出的变量,输出为空。

echo foo在.profile中放入了一个,当然,它被打印了。然后我输入set -vx第一行,打印行的顺序很奇怪;例如,“foo”在“+echo foo”之前打印。

谁能弄清楚发生了什么事吗?

编辑:

当我这样做时ssh kalle@Raspi 'bash -lc "echo \$PATH"',我得到了完整的路径。

编辑2:

我很抱歉造成混乱,当我想运行远程脚本时我非常累,现在我的记忆错误了,但我现在记得我做了什么。

我尝试使用bash -lc它后,仅使用命令不起作用,但我错过了反斜杠!所以我ssh kalle@Raspi 'bash -lc "echo $PATH"'和往常一样,当您将命令字符串赋予另一个命令时,shell 会对该命令字符串执行各种扩展。

因此,在删除引号之后,我们将bash -lc "echo $PATH"其作为单个参数传递ssh并在远程计算机上执行,其中 shell 执行参数替换,即$PATH替换为默认路径它被传递给bash -lc,使后者无用。

然后我很愚蠢地忘记了我正在使用bash -lc,所以我认为ssh kalle@Raspi foo这会导致.profile被阅读,因为我看到了echo我放入.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

编辑:

并非完全不重要:证明它有效且没有副作用。

我把 es 放在, andecho的前面,另一个放在上面的后面。.profile.bashrcset-vars.shechocase ... in ... esac

我应该提到的是,我在所有机器上都使用相同的.profile东西。.bashrc

那么,让我们测试一下:

当我在写这篇文章的机器上打开终端时,我得到:

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

当我 ssh 进入我的 Raspi 时,我得到了完全相同的结果。

当我发出 时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

相关内容