有perl shebang的脚本,中间需要切换到bash

use*_*209 4 scripting bash perl shell-script

我有一个包含两个块的脚本:第一个块是用 perl 编写的,第二个块是用 bash 编写的

如何在脚本中间切换 shell(perl --> bash)?下面附上脚本:

#! /usr/bin/perl -w
#
my @dirs = glob("*.frames");
foreach $dir (@dirs) {
   print "working on $dir\n";
   chdir $dir;
   my @digitfiles = glob ("RawImage_?.tif"); #need to make all files have 2-digit numbering for sort order to be correct
   foreach $file (@digitfiles) {
      my $newfile = $file;
      $newfile =~ s/RawImage_/RawImage_0/;
      rename $file,$newfile;
   }
   my $stackname = "../" . $dir . ".mrc";
   `tif2mrc -s *.tif $stackname`; #IMOD program to stack: -s option means treat input as signed INT
   chdir "../"; #go back up
}

#!/usr/bin/env bash
for f in *.mrc; do mv -- "$f" "${f%%.*}".mrc ; done
Run Code Online (Sandbox Code Playgroud)

cho*_*oba 27

只需在 Perl 中重写循环:

for my $file (glob '*.mrc') {
    ( my $newname = $file ) =~ s/\..*/.mrc/;
    rename $file, $newname or warn "$file: $!";
}
Run Code Online (Sandbox Code Playgroud)

  • 请注意,`mv` 的作用(可以)不仅仅是“重命名”。虽然在这种情况下,使用 `perl` 的 `rename` 可能更接近于 OP 想要的,因为它没有 `mv foo.bar.mrc foo.mrc` 如果 `foo.mrc` 会有的问题` 存在并且是一个目录。 (4认同)

Sté*_*las 19

忽略XY 问题并回答主题中的问题,您可以执行以下操作:

#! /usr/bin/perl
":" || q@<<"=END_OF_PERL"@;

# perl code here

exec "bash", "--", $0, @ARGV;
=END_OF_PERL@

# bash code here
Run Code Online (Sandbox Code Playgroud)

bash将忽略该部分直到该=END_OF_PERL@行,因为它是:

: || something <<"=END_OF_PERL@"
...
=END_OF_PERL@
Run Code Online (Sandbox Code Playgroud)

而第一行,在 perl 中只是两个字符串(":"q@quoted-string@)ORed在一起,所以没有操作。

=END_OF_PERL@inperlpod(文档)部分的开头,因此被perl.

请注意,如果你想从传递变量perlbash,你必须将它们导出到环境(虽然你也可以使用参数;在这里,我们要转发的参数的列表perl收到脚本bash脚本):

$ENV{ENV_VAR} = $perl_var;
Run Code Online (Sandbox Code Playgroud)

代码假定该perl部分不会更改当前工作目录,否则如果$0是相对路径,则传递给bash. 要解决这个问题,您可以在开始时使用脚本的绝对路径:

#! /usr/bin/perl
":" || q@<<"=END_OF_PERL"@;
use Cwd "fast_abs_path";
my $script_path = fast_abs_path $0;

# perl code here

exec "bash", "--", $script_path, @ARGV;
=END_OF_PERL@

# bash code here
Run Code Online (Sandbox Code Playgroud)

这是多语言脚本的一个示例,该脚本是一种以上语言的有效代码。如果您喜欢这些技巧,可以在这里查看更极端的技巧或codegolf Q&A

perldoc perlrun显示了sh+perl多语言的另一个示例,但这次sh首先被调用(对于不支持 she-bangs 的系统)。

  • 这种技巧在起作用时很好,但是当它们失效时,您会失去所有的理智和所有的头发。 (2认同)

gle*_*man 7

你不能切换解释器,但你可以产生一个新的 shell 进程,然后返回到 perl:

my $sh_code = <<'END_SH'
for f in *.mrc; do mv -- "$f" "${f%%.*}".mrc ; done
END_SH

system 'bash', '-c', $sh_code
Run Code Online (Sandbox Code Playgroud)

或者你可以用一个 shell 替换当前的 perl 进程

exec 'bash', '-c', $sh_code
Run Code Online (Sandbox Code Playgroud)

但正如@choroba 所回答的那样,perl 是一种通用语言,几乎可以处理任何任务。