如何在Perl脚本中使用Bash环境变量?

3

我正在尝试在Perl程序中运行Bash命令。 但是,Perl似乎将我的Bash $PWD环境变量误认为是Perl变量。

如何让它只将所有内容视为字符串?

这是我要运行的命令:

my $path = /first/path;
`ln -s $path $PWD/second/path`

那些反引号在Bash中运行第二行代码。使用System()也会遇到相同的问题。有什么想法吗?

2
PWD是由bash(以及其他像zsh这样的shell)导出的;使用/usr/bin/printenv来验证;它是一个“魔术”环境变量。 - Basile Starynkevitch
2
使用 \$ 转义 $ - user3458
2
@RyanSaffer,顺便说一下,一般来说,这种代码是非常危险的。你最好使用本地Perl操作而不是system()或任何等效操作--如果你的路径可能包含$(rm -rf ~)(是的,有可能创建一个实际文件或目录,其中包含该字符串),你不希望将其传递给shell而没有首先进行引用或转义(如果它是作为字符串文字中的$(rm -rf ~)'$(rm -rf ~)',那么即使您尝试通过注入字面单引号来使其安全,也会破坏其引用并造成严重后果)。 - Charles Duffy
1
我确定这个问题是一个重复的问题,但是所选的重复问题是一个糟糕的选择。 - mob
@mob,该列表可以被编辑(由任何具有相关标签徽章的人)。是否愿意提供建议? - Charles Duffy
显示剩余6条评论
1个回答

6
这里有两个问题,一个是关于Bash变量的使用,另一个是关于运行外部命令。
在Perl中有%ENV哈希表,用于存储环境变量。
perl -wE'say $ENV{PWD}'

然而,通常最好在脚本中获取相应的内容,因为对于脚本来说,事情可能有微妙的不同含义或在脚本运行时发生变化。更重要的是,使用shell命令会暴露您面临各种潜在的引号、shell注入和解释问题。例如,您展示的命令是危险的,如Charles Duffy评论中所述。原则上最好使用Perl的丰富功能。请参见下面链接中的内容,了解优点的详细信息:
- Executing system commands safely while coding in Perl - Using system commands in Perl instead of built in libraries/functions [duplicate] 这是一个清晰而详细的说明。
如果您需要运行外部命令,最好完全避免使用 shell,例如使用 system 的多参数形式。如果您还需要命令的输出,Perl 中有各种模块可以提供该功能。请参见下面的链接。
如果您还需要使用 shell 的功能,而不是引用一切以便 shell 更好地接收所需内容,最好使用一个准备好的工具,比如 String::ShellQuote
一些示例: 请注意, qx操作符(反引号)使用/bin/sh,它可能会被降级为Bash。因此,如果您想要Bash,则需要system('/bin/bash', '-c', $cmd),其中$cmd需要仔细构建以避免问题。请参阅示例链接。

这里是与问题背后目标相关的完整示例。

您的程序的工作目录可能与预期不同,具体取决于它如何启动。例如,在chdir之后会发生变化。我不知道您对PWD的确切意图,但在Perl中有核心Cwd::cwdFindBin,用于当前工作目录和脚本所在目录(通常是不同的东西)。

要创建指向$path的符号链接,其中相对路径跟随当前工作目录

use warnings;
use strict;
use Cwd qw(cwd);

my $cwd = cwd;

my $path = '/first/path';

symlink($path, "$cwd/second/path") or die "Can't make a symlink: $!";

如果路径是指脚本的位置,请使用FindBin中的$RealBin而不是cwd。请注意,使用symlink时,不能传递目录而不是链接名称。请参阅this page

@RyanSaffer 我对帖子进行了大幅更新,并提供了具体的答案。 - zdim
回复有些晚了,但这对我帮助很大!谢谢! - Ryan
@RyanSaffer 很好 :) 如果需要更多的解释,请告诉我。 - zdim

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接