스크립트(.bashrc 등)에서 중복된 별칭 및 함수 찾기

스크립트(.bashrc 등)에서 중복된 별칭 및 함수 찾기

이것웹사이트에서는 함수가 별칭보다 빠르다고 말하지만 그는 별칭이 이해하기 쉽다고 정확하게 지적합니다. 별칭은 아주 간단한 것을 원하고 매개변수 전달에 대해 생각할 필요가 없을 때 편리하고 합리적입니다. 그렇다면 내 프로필에는 약 1,000개의 행이 있고 내가 정기적으로 사용하는 기능과 도구의 소스입니다.그리고다른 작업에 참조하고 재사용할 수 있는 기술을 유지하기 위한 수단으로 별칭과 함수가 포함되어 있습니다.

그러나 한 가지 문제는 별칭이 함수보다 우선하며 별칭과 함수를 재정의하면 문제가 발생할 수 있다는 것입니다. 예를 들어 function 을 호출하면 gg스크립트에 예기치 않게 - 라는 함수가 있지만 gg나중에 다시 정의하는 경우에도 마찬가지입니다. 함수를 다시 함수로 정의하면 이전 정의를 덮어씁니다. 구성 파일이 로드되었지만 결국 문제가 발생했습니다. 한 가지 해결책은 모든 별칭을 제거하고 기능만 사용하는 것일 수 있습니다. (누군가 이 작업을 수행했는지 알고 싶습니다. alias m=man이렇게 하는 것보다 이렇게 하는 것이 더 직관적이고 합리적이기 때문입니다 function m() { man $@; }.) 그러나 저는 여전히 함수 재정의에 갇혔습니다. 문제는 이 경우입니다.

"별칭이나 함수의 각 선언에 대해 해당 항목의 재선언(별칭 또는 함수)이 포함된 모든 줄을 표시합니다"라는 대답을 목표로 스크립트를 구문 분석하는 방법이 있습니까?

답변1

다음과 같이 시도해 보세요.

$ cat find-dupes.pl
#!/usr/bin/perl
                                                         
use strict;                                                                                                        
#use Data::Dump qw(dd);                         

# Explanation of the regexes ($f_re and $a_re):
#                                                         
# Both $f_re and $a_re start with '(?:^|&&|\|\||;|&)' to anchor
# the remainder of the expression to the start of the line or
# immediately after a ;, &, &&, or ||. Because it begins with
# '?:', this is a non-capturing sub-expression, i.e. it just    
# matches its pattern but doesn't return what it matches. 
                                                         
# $f_re has two main sub-expressions. One to match 'function name ()'
# (with 'function ' being optional) and the other to match
# 'function name () {' (with the '()' being optional).
#
# Each sub-expression contains more sub-expressions, with one of
# them being a capture group '([-\w.]+)' and the rest being       
# non-capturing (they start with '?:'). i.e. it returns the
# function name as either $1 or $2, depending on which subexp                                               
# matched.
my $f_re = qr/(?:^|&&|\|\||;|&)\s*(?:(?:function\s+)?([-\w.]+)\s*\(\)|function\s+([-\w.]+)\s+(?:\(\))?\s*\{)/;

# $a_re matches alias definitions and returns the name of
# the alias as $1.
my $a_re = qr/(?:^|&&|\|\||;|&)(?:\s*alias\s+)([-\w.]+)=/;

# %fa is a Hash-of-Hashes (HoH) to hold function/alias names and
# the files/lines they were found on. i.e an associative array
# where each element is another associative array.  Search for
# HoH in the perldsc man page.
my %fa;

# main loop, read and process the input
while(<>) {
  s/#.*|^\s*:.*//;  # delete comments
  s/'[^']+'/''/g;   # delete everything inside ' single-quotes
  s/"[^"]+"/""/g;   # delete everything inside " double-quotes
  next if /^\s*$/;  # skip blank lines

  while(/$f_re/g) {
      my $match = $1 // $2;
      #print "found: '$match':'$&':$ARGV:$.\n";
      $fa{$match}{"function $ARGV:$."}++;
  };

  while(/$a_re/g) {
      #print "found: '$1':'$&':$ARGV:$.\n";
      $fa{$1}{"alias $ARGV:$."}++;
  };

  close(ARGV) if eof;
};

#dd \%fa;

# Iterate over the function/alias names found and print the
# details of duplicates if any were found.
foreach my $key (sort keys %fa) {
  my $p = 0;

  # Is this function/alias ($key) defined more than once on
  # different lines or in different files?
  if (keys %{ $fa{$key} } > 1) {
    $p = 1;
  } else {
    # Iterate over the keys of the second-level hash to find out
    # if there is more than one definition of a function/alias
    # ($key) in the same file on the same line ($k)
    foreach my $k (keys %{ $fa{$key} }) {
      if ($fa{$key}{$k} > 1) {
        $p = 1;

        # break out of the foreach loop, there's no need to keep
        # searching once we've found a dupe
        last;
      };
    };
  };

  # print the details if there was more than one.
  print join("\n\t", "$key:", (keys %{$fa{$key}}) ), "\n\n" if $p;
};

주석 처리됨데이터::덤프, printdd라인은 디버깅을 위한 것입니다. 스크립트의 기능과 작동 방식을 더 잘 이해하려면 주석 처리를 제거하세요. dd이 모듈의 함수 출력은 Data::DumpHoH의 구조(및 내용)를 보여주기 때문에 특히 흥미롭습니다 %fa. Data::DumpPerl에는 포함되어 있지 않으며 설치해야 하는 라이브러리 모듈입니다. 어떤 배포판을 사용하고 있는지 언급하지 않았지만 debian/ubuntu/mint/etc를 사용하는 경우 sudo apt install libdata-dump-perl다른 배포판에서는 약간 다른 이름으로 패키지할 수 있습니다. 그렇지 않으면 를 사용하여 설치할 수 있습니다 cpan.

출력 예(주석의 별칭과 일부 더미 함수가 포함된 파일 사용):

$ cat yorsub.aliases 
function foo () { echo ; }
bar () { echo ; }
bar () { echo ; }
function baz () { echo ; } && quux () { echo ; } ; alias xyz=abc; 
type tmux  &> /dev/null && alias t='tmux'
alias cd-='cd -'; alias cd..='cd ..'; alias u1='cd ..'; alias u2='cd ../..'; alias u3='cd ../../..'; alias u4='cd ../../../../..'; alias u5='cd ../../../../../..'; alias u6='cd ../../../../../../..' alias back='cd -'; alias cd-='cd -'; alias .1="cd .."; alias .2="cd ../.."; alias .3="cd ../../.."; alias .4="cd ../../../.."; alias .5="cd ../../../../.."; alias .6='cd ../../../../../../..'
function cd.. { cd .. ; }
function abc () { xyx "$@" }; abc () { xyz } ; function abc { xyz }; alias abc=xyz
$ ./find-dupes.pl yorsub.aliases    
abc:
        function yorsub.aliases:8
        alias yorsub.aliases:8

bar:
        function yorsub.aliases:3
        function yorsub.aliases:2

cd-:
        alias yorsub.aliases:6

cd..:
        alias yorsub.aliases:6
        function yorsub.aliases:7

답변2

간단한 grep은 정의를 찾지만 재정의를 확인하지는 않습니다.

$ grep -onE 'alias [[:alnum:]_]+=|[[:alnum:]_]+\(\)' .bashrc .aliases
.bashrc:47:alias foo=
.bashrc:47:alias bar=
.bashrc:49:asfdasdf()
.aliases:3:alias ls=
.aliases:6:alias foo=

다음 Perl 코드 줄은 재정의를 표시할 수 있도록 개수를 유지합니다.

$ perl -lne 'while( /alias (\w+)=|(\w+)\(\)/g ) { 
                 $name = $1 // $2; $count{$name} += 1; 
                 printf "\"%s\" %s in %s line %s%s\n", $name, $count{$name} > 1 ? "REDEFINED" : "defined", $ARGV, $. 
             }' .bashrc .aliases 
"foo" defined in .bashrc line 47
"bar" defined in .bashrc line 47
"asfdasdf" defined in .bashrc line 49
"ls" defined in .aliases line 53
"foo" REDEFINED in .aliases line 56

(입력 파일의 순서는 "재정의"로 표시되지 않은 파일에 영향을 줍니다.)

관련 정보