두 개의 블록이 있는 스크립트가 있습니다. 첫 번째 블록은 Perl로 작성되고 두 번째 블록은 Bash로 작성되었습니다.
스크립트 중간에 쉘(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
답변1
Perl로 루프를 다시 작성하세요.
for my $file (glob '*.mrc') {
( my $newname = $file ) =~ s/\..*/.mrc/;
rename $file, $newname or warn "$file: $!";
}
답변2
소홀히 하다XY 문제이 주제의 질문에 답하려면 다음을 수행하십시오.
#! /usr/bin/perl
":" || q@<<"=END_OF_PERL"@;
# perl code here
exec "bash", "--", $0, @ARGV;
=END_OF_PERL@
# bash code here
bash
=END_OF_PERL@
이 줄 앞의 부분은 다음과 같은 이유로 무시됩니다 .
: || something <<"=END_OF_PERL@"
...
=END_OF_PERL@
그리고 첫 번째 줄에는 Perl에는 두 개의 문자열( ":"
및q@quoted-string@
)이 함께 OR되어 연산이 이루어지지 않습니다.
=END_OF_PERL@
in은 perl
a의 시작이다pod
(문서)따라서 일부는 무시됩니다 perl
.
perl
에서 로 변수를 전달 하려면 bash
해당 변수를 환경으로 내보내야 합니다(매개변수를 사용할 수도 있지만 여기서는 스크립트에서 받은 매개변수 목록을 perl
스크립트로 전달합니다 bash
).
$ENV{ENV_VAR} = $perl_var;
코드에서는 이 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
이것은 여러 언어로 유효한 코드인 다국어 스크립트의 예입니다. 이 팁이 마음에 든다면 확인해 보세요.더 극단적인 것은여기 아니면 저거코드골프 Q&A.
perldoc perlrun
sh
+multilingual의 또 다른 예가 표시되어 있지만 perl
이번에 sh
는 먼저 호출됩니다(셔뱅을 지원하지 않는 시스템의 경우).
답변3
당신은 할 수 없습니다변화하지만 새로운 쉘 프로세스를 생성한 다음 Perl로 돌아갈 수 있습니다.
my $sh_code = <<'END_SH'
for f in *.mrc; do mv -- "$f" "${f%%.*}".mrc ; done
END_SH
system 'bash', '-c', $sh_code
또는 현재 Perl 프로세스를 Shell로 대체할 수 있습니다.
exec 'bash', '-c', $sh_code
그러나 @choroba가 답변했듯이 Perl은 거의 모든 작업을 처리할 수 있는 범용 언어입니다.
답변4
Perl에서 모든 작업을 수행할 수도 있고 쉘 스크립트에서 모든 작업을 수행할 수도 있습니다. 그러나 혼합 언어는 약간 혼란스러운 경우가 많습니다.
쉘 스크립트 버전은 다음과 같습니다.그것은 마치이것은( bash
예를 들어):
#!/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
또는 약간 더 관용적입니다(일반 now 를 사용 sh
하지만 find
이해할 수 있는 a 를 사용함 -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
(두 예제 모두 파일 이름 생성에 대해서만 테스트되었습니다.)
이름이 바뀐 각 파일에 대한 일부 출력을 얻으려면 sh -c
로 변경 하거나 .sh -cx
-print
-execdir
를 사용하면 -execdir
찾은 파일의 디렉터리를 작업 디렉터리로 사용하여 주어진 쉘 명령이 실행됩니다. {}
(그리고 $1
서브쉘 내에서)은 발견된 파일의 기본 이름이 됩니다.
만약에tif2mrc
필요TIFF 파일의 디렉터리에서 실행하고 루프를 다음으로 변경합니다.
for d in *.frames; do
printf 'Processing "%s"...\n' "$d"
(cd "$d" && tif2mrc -s *.tif "../${d%%.*}.mrc" )
done
Perl에서는 백틱을 사용하여 쉘 명령을 실행하면 해당 명령의 출력이 반환됩니다. 대신 사용할 수 있습니다
system("tif2mrc -s *.tif $stackname");
의 출력에 관심이 없다면 tif2mrc
.
또한 디렉터리를 앞뒤로 변경하는 스크립트나 프로그램을 읽는 것도 혼란스러울 수 있습니다. 디렉토리가 존재하지 않는 경우 원치 않는 일이 발생할 수도 있습니다( chdir("..");
그러면 디렉토리 수준을 너무 높게 올리십시오).
이를 올바르게 수행하려면 마지막 쉘 예제와 같이 이동된 작업 디렉토리로 명령을 실행하거나 Perl의 초기 반환 코드를 올바르게 확인하십시오 chdir()
(이로 인해 코드를 읽고 따라가기가 여전히 어려울 수 있음).