
これウェブサイトでは、関数がエイリアスよりも速いと言いますが、彼はエイリアスが理解しやすいと正確に指摘しています。エイリアスは非常に単純なものが必要で、パラメータ渡しについて考える必要がない場合に便利で合理的です。その場合、私のプロフィールには約1,000行があり、私が定期的に使用する機能とツールのソースです。そして他のタスクに参照して再利用できる技術を維持するための手段として、エイリアスと関数が含まれています。
しかし、問題の1つは、別名が関数よりも優先され、別名と関数をオーバーライドすると問題が発生する可能性があることです。たとえば、 function を呼び出すと、gg
スクリプトに予期せず - という関数がありますが、gg
後で再定義する場合も同様です。関数を関数として定義すると、以前の定義が上書きされます。構成ファイルがロードされましたが、最終的に問題が発生しました。 1つの解決策は、すべてのエイリアスを削除して機能のみを使用することです。 (誰かがこれをしたかどうかを知りたいのですが、これよりも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;
};
注釈付きデータ::ダンプ、print
およびdd
行はデバッグ用です。スクリプトの機能と仕組みをよりよく理解するには、コメントを外してください。dd
このモジュールの関数出力は、Data::Dump
HoHの構造(および内容)を示すため、特に興味深いものです%fa
。 Data::Dump
Perlには含まれておらず、インストールする必要があるライブラリモジュールです。どのディストリビューションを使用しているかについて言及していませんが、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
(入力ファイルの順序は、「オーバーライド」としてマークされていないファイルに影響します。)