在 Perl 中,執行反引號的默認 shell 是 sh。我想改用 bash 以獲得更豐富的語法。到目前為止,我發現建議的解決方案是
`bash -c \"echo a b\"`
明顯的缺點是轉義的雙引號,這意味著我將很難在我的 bash 引數中使用雙引號。例如,如果我想在 bash 中運行需要雙引號的命令
echo "a'b"
上面的方法會很別扭。
Perl 的 system() 呼叫有一個解決這個問題的方法:使用 ARRAY args,
system("bash", "-c", qq(echo "a'b"));
這使我原來的 bash 命令保持不變,而且幾乎總是如此。
我也想在反引號中使用 ARRAY args。是否可以?感謝您的建議
uj5u.com熱心網友回復:
一方面,可以提交一份清單到qx;它被插入到一個字串中,然后傳遞給其中一個execvp或一個外殼(參見qx,以及本文的第二部分和評論)。如果你需要一個 shell,那么大概該字串包含 shell 元字符,所以它通過 shell。
my @cmd = qw(ls -l "dir with spaces");
#my @cmd = qw(ls -l "dir with spaces" > outfile);
my @out = qx(@cmd);
print for @out;
我創建了一個"dir with spaces"目錄,其中包含一個檔案進行測驗。(對于其中帶有引號的命令"...",使用 shell。)
接下來,我原則上會推薦一個模塊來撰寫這些 shell 命令,而不是通過一個釘子來正確地轉義并傳遞它,比如String::ShellQuote
use String::ShellQuote qw(shell_quote);
my @cmd = ('ls', '-l', q(dir with spaces));
my $quoted = shell_quote(@cmd);;
my @out = qx($quoted);
#my @out = qx($quoted > outfile);
print for @out;
我使用q(...)單引號的運算子形式來演示另一種方式(對于包含單引號也很有用);這個簡單的例子沒有必要。仍然需要注意細節;這是使用復雜外部命令的本質,任何方法或工具都無法完全避免。
至于 running bash,請注意通常sh委托給您系統上的默認排序 shell,并且在許多系統上bash使用它。但是,如果它不在您的范圍內,則bash -c在命令中使用的一種方法是首先準備命令,然后將其添加到qx字串中
my @cmd = ('ls', '-l', q(dir with spaces));
my $quoted = shell_quote(@cmd);
my @out = qx(bash -c "$quoted");
#my @out = qx(bash -c "$quoted" > outfile);
print for @out;
我想再提幾點:
那
qx是遠古的惡魔。使用現代工具/模塊運行外部命令怎么樣?為了準備您所涉及的 bash 字串,可能還有更多作業要做,但其他一切都會更好。選項比比皆是。例如IPC::System::Simple具有少量實用功能
使用Capture::Tiny
system以您喜歡的語法包裝呼叫IPC::Run可以做任何和所有這些,然后做得更多
為什么要使用具有 Perl(遠)優越的豐富性的外部命令?它是一門完整的、非常完整的編程語言,而不是具有一些編程能力的命令解釋器。如果您需要 shell 的功能,為什么不通過 shell 運行這些東西并在 Perl 中做所有其他事情呢?
uj5u.com熱心網友回復:
Capture::Tiny是一個很好的選擇:正如 SYNOPSIS 所示,您可以這樣做
use Capture::Tiny 'capture';
my ($output, $error_output, $exit_code) = capture {
system(@whatever);
};
capture_stdout如果您想要更簡單的反引號行為,還可以使用 system inside 。
此外,它非常通用,可以處理 Perl 代碼(甚至是執行奇怪操作的 Perl 代碼)以及外部程式,因此在您的工具箱中擁有它是一件好事。
uj5u.com熱心網友回復:
給定
my @cmd = ( "bash", "-c", qq(echo "a'b") );
您可以使用以下任何一種:
use Shell::Quote qw( shell_quote );
my $cmd = shell_quote( @cmd );
my $output = `$cmd`;
die "Can't spawn child: $!\n" if $? == -1;
die "Child killed by signal ".( $? & 0x7F )."\n" if $? & 0x7F;
die "Child exited with error ".( $? >> 8 )."\n" if $? >> 8;
或者
use IPC::System::Simple qw( capturex );
my $output = capturex( @cmd );
或者
use IPC::Run qw( run );
run \@cmd, '>', \my $output;
die "Child killed by signal ".( $? & 0x7F )."\n" if $? & 0x7F;
die "Child exited with error ".( $? >> 8 )."\n" if $? >> 8;
uj5u.com熱心網友回復:
我有以下作業的子
sub bash_output {
my ($cmd) = @_;
open my $ifh, "-|", "bash", "-c", $cmd or die "cannot open file handler: $!";
my $output = "";
while (<$ifh>) {
$output .= $_;
}
close $ifh;
return $output;
}
print "test bash_output()\n";
my @strings = (
qq(echo "a'b"),
'echo $BASH_VERSION',
'[[ "abcde" =~ bcd ]] && echo matched',
'i=1; ((i )); echo $i',
);
for my $s (@strings) {
print "bash_output($s) = ", bash_output($s), "\n";
}
輸出是
bash_output(echo "a'b") = a'b
bash_output(echo $BASH_VERSION) = 4.4.20(1)-release
bash_output([[ "abcde" =~ bcd ]] && echo matched) = matched
bash_output(i=1; ((i )); echo $i) = 2
我的回答很啰嗦,但它滿足了我的需要。我希望 Perl 有一個內置的解決方案,就像它處理 system() 呼叫的方式一樣,我仍然希望。
uj5u.com熱心網友回復:
您可以更改 perl 使用的外殼:
$ENV{PERL5SHELL} = "bash";
my $out = qx{echo "Hello ' world from bash \$BASH_VERSION"};
print($out);
uj5u.com熱心網友回復:
您可以使用單引號作為分隔符,qx如下所示:
my $out = qx'bash -c "echo a b"';
這將根據perlop保護命令免受 Perl 的雙引號內插。
不幸的是,這不適用于單引號。echo "'"例如,如果您想這樣做,則需要以下內容:
my $out = `bash -c \"echo \\\"'\\\"\"`;
編輯:
為了幫助您管理引號的轉義,您可以使用如下輔助函式:
use experimental qw(signatures);
sub bash_backticks($code) {
$code =~ s/'/'"'"'/g;
`bash -c '$code'`
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/425546.html
