Apenas reescreva o loop em Perl:
for my $file (glob '*.mrc') {
( my $newname = $file ) =~ s/\..*/.mrc/;
rename $file, $newname or warn "$file: $!";
}
Eu tenho um script com dois blocos: O primeiro bloco é escrito em perl, o segundo bloco é escrito em bash
Como faço para alternar shells (perl - > bash) no meio do script? Script anexado abaixo:
#! /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
Apenas reescreva o loop em Perl:
for my $file (glob '*.mrc') {
( my $newname = $file ) =~ s/\..*/.mrc/;
rename $file, $newname or warn "$file: $!";
}
Ignorando o problema XY e para responder à pergunta no assunto, você poderia fazer:
#! /usr/bin/perl
":" || q@<<"=END_OF_PERL"@;
# perl code here
exec "bash", "--", $0, @ARGV;
=END_OF_PERL@
# bash code here
bash
ignorará a parte até a linha =END_OF_PERL@
porque é:
: || something <<"=END_OF_PERL@"
...
=END_OF_PERL@
enquanto a primeira linha, em perl, é apenas duas strings ( ":"
e q@quoted-string@
) ORed juntos, então um no-op.
=END_OF_PERL@
in perl
é o início de uma seção pod
(documentação) , ignorada por perl
.
Observe que, se quiser passar variáveis de perl
para bash
, será necessário exportá-las para o ambiente (embora você também possa usar argumentos; aqui estamos encaminhando a lista de argumentos para o script perl
recebido para o script bash
):
$ENV{ENV_VAR} = $perl_var;
O código assume que a parte perl
não altera o diretório de trabalho atual, pois caso contrário, se $0
fosse um caminho relativo, ele se tornaria inválido quando passado para bash
. Para contornar isso, você pode pegar um caminho absoluto do script no começo com:
#! /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
Esse é um exemplo de um script poliglota, um script que é um código válido em mais de um idioma. Se você gosta desses truques, pode dar uma olhada em aquele mais radical aqui ou que codegolf Q & A .
perldoc perlrun
mostra outro exemplo de sh
+ perl
poliglota, mas desta vez com sh
sendo chamado primeiro (para sistemas que não suportam shebags).
Você não pode alternar intérpretes, mas você pode gerar um novo processo shell e, em seguida, retornar ao perl:
my $sh_code = <<'END_SH'
for f in *.mrc; do mv -- "$f" "${f%%.*}".mrc ; done
END_SH
system 'bash', '-c', $sh_code
Ou você pode substituir o processo perl atual por um shell
exec 'bash', '-c', $sh_code
Mas, como o @choroba responde, o perl é uma linguagem de uso geral e pode lidar com praticamente qualquer tarefa.
Você pode fazer tudo em Perl ou tudo em um script de shell. No entanto, misturar idiomas é um pouco confuso.
A versão do script de shell pode parecer algo como isso (com bash
, por exemplo):
#!/bin/bash
dirs=( *.frames )
for dir in "${dirs[@]}"; do
printf 'Working on "%s"\n' "$dir"
cd "$dir"
digitfiles=( RawImage_?.tif )
for file in "${digitfiles[@]}"; do
newfile="RawImage_0${file#RawImage_}"
mv "$file" "$newfile"
done
stackname="../$dir.mrc"
tif2mrc -s *.tif "$stackname"
cd ..
done
for f in *.mrc; do
mv -- "$f" "${f%%.*}".mrc
done
Ou, um pouco mais idiomático (agora com% normalsh
, mas usando um find
que entende -execdir
):
#!/bin/sh
echo 'Renaming TIFF files'
find *.frames -type f -name 'RawImage_?.tif' \
-execdir sh -c 'mv "$1" "RawImage_0${1#RawImage_}"' sh {} ';'
for d in *.frames; do
printf 'Processing "%s"...\n' "$d"
tif2mrc -s "$d"/*.tif "${d%%.*}.mrc"
done
(ambos os exemplos são testados apenas no que diz respeito à geração de nome de arquivo)
Altere sh -c
para sh -cx
para obter um pouco de saída para cada arquivo renomeado ou adicione -print
antes de -execdir
.
Com -execdir
, o comando shell fornecido será executado com o diretório do arquivo encontrado como seu diretório de trabalho. {}
(e $1
dentro da subshell) será o nome base do arquivo encontrado.
Se tif2mrc
precisar para ser executado dentro do diretório dos arquivos TIFF, altere o loop para
for d in *.frames; do
printf 'Processing "%s"...\n' "$d"
(cd "$d" && tif2mrc -s *.tif "../${d%%.*}.mrc" )
done
Observe que, em Perl, o uso de backticks para executar um comando shell retornará a saída desse comando. Você pode usar
system("tif2mrc -s *.tif $stackname");
se você não estiver interessado na saída de tif2mrc
.
Além disso, é confuso ler um script ou programa que altera diretórios de um lado para outro. Além disso, pode levar a coisas indesejadas, se um diretório não existir (o chdir("..");
, então, levaria você a um nível de diretório muito alto).
Para fazer isso corretamente, execute o comando com um diretório de trabalho deslocado, como no meu último exemplo de shell, ou verifique corretamente o código de retorno do chdir()
inicial em Perl (isso ainda levaria ao código que pode ser difícil de ler e seguir).
Tags bash perl scripting shell-script