Bash - 함수에 사용된 함수를 다른 스크립트에 재귀적으로 복사하는 방법(내 .bashrc 파일을 다른 스크립트와 공유하지만 관련 부분만 공유)

Bash - 함수에 사용된 함수를 다른 스크립트에 재귀적으로 복사하는 방법(내 .bashrc 파일을 다른 스크립트와 공유하지만 관련 부분만 공유)

.bashrc내 파일을 어떻게 공유하되 관련 부분만 공유하나요 ?

예를 들어 다음 위치에 5개의 함수를 만들었습니다 .bashrc.

f1() {
...
}

f2() {
   f1
   ...
}

f3() {
   f2
   ...
}

f4() {
   f1
   f3
   ...
}

f5() {
   ...
}

f5()사례 1: 동료들과 공유하고 싶어서 복사해서 f5()붙여넣기만 하면 됩니다.

사례 2: 공유하고 싶기 때문에 복사 하여 재귀적으로 합산하고 f3()싶습니다 .f3()f2()f1()

사례 3: 공유하고 싶기 때문에 AND 를 재귀적으로 f4()복사하고 싶지만 둘 다 AND로 호출 되더라도 한 번만 복사하고 싶습니다 .f3()f2()f1()f1()f1()f3()f2()

지금은 수동으로 찾아서 복사하지만 오류가 발생하기 쉽습니다. 이 작업을 자동으로 수행할 수 있습니까? 저는 파이썬을 사용하지 않습니다. 모든 함수가 동일한 .bashrc파일에 있고 내가 정의한 bash 함수라고 가정합니다.

답변1

구경하다flatten.sh. 나는 모든 별칭과 함수를 쉘 스크립트에 소스화하고 필요한 대로 평면화할 수 있도록 이 글을 썼습니다. 그래서 지금 여러분이 처한 상황과 비슷합니다.

따라서 example.lib다음과 같은 것(또는 귀하의 것 .bashrc):

f1() {
  echo "I am f1"
}

f2() {
   f1
}

f3() {
   f2
}

f4() {
   f1
   f3
}

f5() {
  :
}

example.sh그리고 다음과 같은 스크립트:

#!/usr/bin/env -S bash - 
. /path/to/example.lib

f4

너는 달려가서 flatten.sh example.sh얻는다

#!/usr/bin/env -S bash - 
f1() {
  echo "I am f1"
}

f2() {
   f1
}

f3() {
   f2
}

f4() {
   f1
   f3
}

f4

답변2

다음 Perl 스크립트는 스크립트에서 함수 이름과 정의를 추출하기 위한 개념 증명 데모입니다. %funcs각 함수 코드를 포함하는 해시(연관 배열)를 구축합니다 . 그런 다음 각 함수 정의를 검색하여 해당 함수에서 호출되는 다른 함수를 찾고 해당 정보를 해시("HoH")라는 해시에 저장합니다. 해시는 각 요소가 다른 해시입니다. 참조 man perldsc) %contains.

마지막으로 명령줄에 제공된 함수 이름 목록에서 시작하여 인쇄할 함수 목록( 이라는 또 다른 해시 %out)을 작성한 다음 인쇄합니다.

이 스크립트는 개념적으로 매우 단순하고 무차별적입니다. 성능이나 단순성을 위해 코드를 최적화하려는 노력은 전혀 이루어지지 않았습니다.

참고: 이것은 완전한 쉘 코드 파서가 아닙니다(기껏해야 간단한 정규식 토큰 일치자입니다). 위의 예제 함수를 정의하는 쉘 코드, 내 자신의 ~/.bashrc 및 내장 함수 출력의 stdin에 대해서만 set테스트 되었습니다(정의된 함수와 변수를 내부 help set또는 외부에서도 인쇄합니다). bash 매뉴얼 페이지).

다른 쉘 코드가 이를 깨뜨릴 수도 있습니다(사실 가능성이 높습니다). 이 경우 (적어도) 토큰 추출 정규식을 수정해야 하며, 조회 함수 정의 시작 부분의 정규식도 수정해야 합니다. 인용된 문자열과 주석을 제거하는 코드가 있을 수도 있습니다. 이는 실패 가능성이 가장 높은 세 가지 지점입니다.

#!/usr/bin/perl

use strict;
use v5.10;

# primitive arg handling to separate function names from
# input files on the command line.
#
# if an argument is a filename that exists, treat it as
# an input file.  If not, treat it as a function name to
# search for.

my (@args,%find) = ();
foreach (@ARGV) {
  if (-e $_) {
    push @args, $_; # array of input files to process
  } else {
    $find{$_} = 1;  # hash of function name(s) to search for.
  }
};
@ARGV = @args;

# Main loop, read and process the input.
# Build up a hash called %funcs with key = function name
# and val = function code.
my %funcs = ();
while(<>) {
  state ($fname, $in_func, $counter);
  # state variables:
  # $fname   - name of current function
  # $in_func - are we in a function definition
  # $counter - how many { and } have we seen in this function?

  if (/^(?:function)?\s*([^\$(=\s]*)\s*[(]/) {
    $fname   = $1;
    $funcs{$fname} = $_;
    $in_func = 1;

    # cuddled braces begin on same line as function name. uncuddled don't.
    my $cuddled  = () = $_ =~ (/{/g); # count of { on this line
    next unless $cuddled;
    $cuddled    -= () = $_ =~ (/}/g); # subtract count of }s on line
    $counter = $cuddled;

    $in_func = $cuddled;
    next;
  };

  if ($in_func) {
    $funcs{$fname} .= $_;

    my $plus  = () = $_ =~ (/{/g); # count of {s on line
    my $minus = () = $_ =~ (/}/g); # count of }s on line

    $counter += $plus - $minus;

    $in_func = ($counter > 0);
  }
};

###
### Now determine which functions to print, then print them.
###

my %contains = ();
my $match = join("|", keys %funcs);

foreach my $f (keys %funcs) {
  # ignore everything in quoted strings and comments by
  # copying the current function to variable $function and
  # stripping unwanted junk. ignore unquoted array references  too.
  my $function;
  ($function = $funcs{$f}) =~ s/"[^"]*"|'[^']*'|#.*$|\$\{[^}]}//mg;

  # find tokens that *look like* calling one of our known function names
  my (@tokens) = ($function =~ /(?:^|;|&{1,2}|\|{1,2}|[({])\s*($match)\b(?!=)/gm);

  foreach my $t (@tokens) {
    # if the current token $t is one of our known functions
    # then add it to %contains{$f}
    if (defined($funcs{$t})) {
      $contains{$f}->{$t} = 1;
    };
  };
};

my %out = %find;

# Iterate over each function's name.  Add the name to %out 
# and %find if it is called from within a wanted function.
# Repeat until %out doesn't change.
my %old_out;
do {
  %old_out = %out;
  foreach my $f (keys %find) {
    foreach my $t (keys %{ $contains{$f} }) {
      $out{$t}  = 1; # add to output hash
      $find{$t} = 1; # add to list of function names to search for
    };
  };
} until %out == %old_out;

# print the functions listed in %out, sorted by name
# otherwise will be printed in pseudo-random order as hashes
# are un-ordered.
foreach my $f (sort keys %out) {
  print $funcs{$f}, "\n";
};

예를 들어 다른 이름으로 저장하면 extract-funcs.pl실행 파일이 chmod +x다음과 같이 실행됩니다(함수 정의 복사본 사용 functions.txt).

$ ./extract-funcs.pl functions.txt f1
f1() {
...
}

f1다른 함수에 대한 호출이 포함되어 있지 않으므로 f1만 인쇄됩니다.

$ ./extract-funcs.pl functions.txt f2
f1() {
...
}

f2() {
   f1
   ...
}

f2f1에 대한 호출이 포함되어 있으므로 f1과 f2가 인쇄됩니다.

$ ./extract-funcs.pl functions.txt f4
f1() {
...
}

f2() {
   f1
   ...
}

f3() {
   f2
   ...
}

f4() {
   f1
   f3
   ...
}

f4f1 및 f3에 대한 호출이 포함되고, f3에는 f2에 대한 호출이 포함되며, f2에는 f1에 대한 호출이 포함되므로 f1, f2, f3 및 f4가 인쇄됩니다. f1은 f4 및 f2에서 호출되더라도 한 번만 인쇄합니다.

붙여 넣기 또는 xsel -i -b편집 메뉴에서 사용하기 위해 출력을 클립보드로 파이프할 수 있습니다 . 또는 마우스 가운데 버튼을 클릭하여 붙여넣으려면 X의 기본 선택 항목에 복사하세요. 바라보다 .CtrlVShiftInsxsel -iman xsel

관련 정보