为啥在从 C# 创建的进程中运行 bash 命令时我的 $PATH 不同?

Posted

技术标签:

【中文标题】为啥在从 C# 创建的进程中运行 bash 命令时我的 $PATH 不同?【英文标题】:Why is my $PATH different when running bash commands inside a process created from C#?为什么在从 C# 创建的进程中运行 bash 命令时我的 $PATH 不同? 【发布时间】:2021-07-14 07:14:51 【问题描述】:

我在 CentOS 上有一个 .NET 5 程序,它使用 .service 文件从 systemd 服务启动。它需要通过命令行执行另一个程序,所以我写了这些代码:

var processStartInfo = new ProcessStartInfo()

    FileName = "/bin/bash",
    Arguments = "-c \"echo $PATH\"",
    WorkingDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)
;

var process = Process.Start(processStartInfo);
process.WaitForExit();

当从 CentOS 的终端执行时,echo $PATH 返回/usr/lib64/qt-3.3/bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:/home/test_user/.local/bin:/home/test_user/bin。 但是使用上面的代码运行echo $PATH给我/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin

为什么 2 个 $PATH 值不同? 搜索 $PATH 给了我一些关于 /etc/profile~/.bash_profile/etc/bash.bashrc~/.bashrc 的结果,但我不确定如何解释这些文件。

【问题讨论】:

在您从 C# 中启动 bash 进程的方式中,它是一种非交互式、非登录调用。在您的终端中,它是一个交互式外壳。你没有说你是如何配置你的终端的,所以我不知道它是登录还是非登录调用。所有这些都会影响执行哪些启动文件。但是,PATH 应该在环境中。如果您从终端启动了 C# 程序,它应该继承 PATH,因此错误可能在其他地方。你没有说你是如何运行你的程序的。 @user1934428 在 CentOS 上的应用程序启动器中,我选择 Konsole 来启动终端。 C# 程序通过 systemd 服务使用 .service 文件启动,其中 ExecStart=/usr/bin/dotnet /var/www/my-program/MyProgram.dll, User=root。我不确定其中任何一个是否会被视为“登录调用”。 至少它解释了为什么 PATH 没有被调用。至少它是一个非交互式调用,并且您的.bashrc 不会被处理。请参阅 bash 手册页的 INVOCATION 部分,了解 bash 进程启动时会发生什么。 @user1934428 我对交互式 shell 描述并不完全清楚。所以我使用 Konsole 是在调用一个交互式 shell,但是像我的代码一样从 C# 启动是在调用一个非交互式 shell?我也尝试查看 $BASH_ENV 的值,但 echo $BASH_ENV 给了我一个空行。 很可能,是的。为什么它应该是交互式的?您可以(如手册页中所述)打印变量$-。如果它包含字母i,则您处于交互式外壳中。 BASH_ENV 始终为空,除非您在某处明确设置它,但我不明白您为什么要这样做。我不明白你想从打印它中获得什么...... 【参考方案1】:

问题是上面的代码调用了一个非交互式shell,而不是像使用系统控制台时那样的交互式shell。 From GNU's Bash Reference Manual, section 1.2:

Shell 可以交互或非交互方式使用。在互动 模式,它们接受从键盘输入的输入。执行时 shell 以非交互方式执行从文件中读取的命令。

交互式和非交互式 shell 在启动时检查 $PATH 值的方法不同,如第 6.2 节所述。作为交互式 shell,Bash 可以从 etc/profile~/.bash_profile~/.bash_login~/.profile 读取以检查 $PATH 值,但作为非交互式 shell,Bash 只接受环境变量 BASH_ENV 中的任何内容用作$PATH 值:

以非交互方式调用

当 Bash 以非交互方式启动时, 运行一个 shell 脚本,例如,它在 环境,如果它出现在那里就扩展它的价值,并使用 扩展值作为要读取和执行的文件的名称。

【讨论】:

以上是关于为啥在从 C# 创建的进程中运行 bash 命令时我的 $PATH 不同?的主要内容,如果未能解决你的问题,请参考以下文章

从 Mono C# 运行 Bash 命令

Json String Parsing 在从 MSDOS 运行时有效,但在 Windows 上的 Ubuntu 上的 Bash 中无效 [重复]

为啥我必须 sudo 来自守护进程的命令?

Linux 学习笔记 更多的bash shell命令

使用子进程运行多个 bash 命令

在bash中杀死一个进程[重复]