Perl Shebang이 포함된 스크립트가 있는데 중간에 Bash로 전환해야 합니다.

Perl Shebang이 포함된 스크립트가 있는데 중간에 Bash로 전환해야 합니다.

두 개의 블록이 있는 스크립트가 있습니다. 첫 번째 블록은 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은 perla의 시작이다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 perlrunsh+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()(이로 인해 코드를 읽고 따라가기가 여전히 어려울 수 있음).

관련 정보