因此,我有一个充满测试命令的文件,我喜欢对我的一些函数运行这些命令,以确保它们正确处理所有可能的情况。虽然有重复的命令是没有意义的。以下是一些示例:
rap ,Xflg MIT X11
rap ,XPBfl 'MITER'
rap ,Bflg share git-grep
rap ,bfl X11
rap ,Bfl xzfgrep
rap ,Bf X11
...我的函数“rap”使用逗号而不是破折号来指示字母选项的开头,然后是一些参数。由于这些选项的顺序并不重要:
rap ,Bf X11
rap ,fB X11
...是完全相同的命令。当然,很容易从文件中删除重复行,但是为了避免上述问题,我想要做的是按字母顺序对选项进行排序,以便上面的结果:
rap ,Bf X11
rap ,Bf X11
...然后我就可以删除重复项。没有英雄气概就能完成这样的事吗?请注意,这不是对选项列表进行排序,而是对选项本身进行排序。
答案1
另一种perl
变体:
$ perl -pe 's{^rap ,\K\S+}{join "", sort split //, $&}e' file
rap ,Xfgl MIT X11
rap ,BPXfl 'MITER'
rap ,Bfgl share git-grep
rap ,bfl X11
rap ,Bfl xzfgrep
rap ,Bf X11
对于在大写字母之前有小写字母的额外要求,您可以依靠以下事实:在 ASCII 中,'x'
is 'X' ^ 32
(和'X'
is 'x' ^ 32
):
$ perl -pe 's{^rap ,\K\S+}{join "", sort {(ord($a)^32) <=> (ord($b)^32)} split //, $&}e' file
rap ,fglX MIT X11
rap ,flBPX 'MITER'
rap ,fglB share git-grep
rap ,bfl X11
rap ,flB xzfgrep
rap ,fB X11
答案2
您可以使用 perl 捕获逗号后面的单词字符序列,将结果拆分为数组,对其进行排序并替换结果:
$ perl -pe 's{(?<=,)(\w+)}{join "", sort split(//, $1)}e' yourfile
rap ,Xfgl MIT X11
rap ,BPXfl 'MITER'
rap ,Bfgl share git-grep
rap ,bfl X11
rap ,Bfl xzfgrep
rap ,Bf X11
根据要求,这是一种(可能不是最佳的)方法,可以将所有小写字母选项排序在所有大写字母选项之前:
$ perl -pe 's{(?<=,)(\w+)}{@opts = split(//,$1); join "",
(sort grep /[[:lower:]]/,@opts), (sort grep /[^[:lower:]]/, @opts)
}e' yourfile
rap ,fglX MIT X11
rap ,flBPX 'MITER'
rap ,fglB share git-grep
rap ,bfl X11
rap ,flB xzfgrep
rap ,fB X11
答案3
使用 GNU awk 进行sorted_in
而且,由于我们无论如何都使用 gawk,还有一些其他方便但不必要的扩展,我们可以应用装饰-排序-取消装饰习惯用法通过将其放在1
任何小写字符前面和大写2
字符前面,强制小写字符在大写字符之前进行排序,然后在打印之前再次删除这些装饰:
$ cat tst.awk
BEGIN { PROCINFO["sorted_in"] = "@val_str_asc" }
match( $0, /^(\s*\S+\s*,)(\S+)(.*)/, a ) {
gsub( /[[:lower:]]/, "1 &,", a[2] ) # Decorate
gsub( /[[:upper:]]/, "2 &,", a[2] )
sorted = ""
split(a[2],opts,",")
for ( idx in opts ) { # Sort
sorted = sorted opts[idx]
}
gsub( /[[:digit:] ,]/, "", sorted ) # Undecorate
$0 = a[1] sorted a[3]
}
{ print }
$ awk -f tst.awk file
rap ,fglX MIT X11
rap ,flBPX 'MITER'
rap ,fglB share git-grep
rap ,bfl X11
rap ,flB xzfgrep
rap ,fB X11
答案4
如果我们用破折号替换输入文件中的逗号,我们可以getopts
像往常一样使用来解析rap
函数的选项。
该更改可以通过 来完成sed
,假设我们只需要rap ,
在任何行的开头更改为rap -
,它看起来像这样:
sed 's/^rap ,/rap -/' file.in >file
. ./file
然后,假设该rap
函数之前已经声明过,我们就可以简单地在脚本中获取生成的文件。
解析rap
函数中的选项:
rap () {
OPTIND=1
unset -v B_flag P_flag X_flag
unset -v b_flag f_flag g_flag l_flag
while getopts BPXbfgl opt; do
case $opt in
B) B_flag=true ;;
P) P_flag=true ;;
X) X_flag=true ;;
b) b_flag=true ;;
f) f_flag=true ;;
g) g_flag=true ;;
l) l_flag=true ;;
*) echo 'Error' >&2; return 1
esac
done
shift "$(( OPTIND - 1 ))"
# Act on set flags here.
if "${f_flag-false}"; then
echo 'The -f option was used'
fi
# The non-options are available in "$@".
printf 'Other argument: %s\n' "$@"
printf -- '---\n'
}
请注意,通过在循环中设置标志变量while
并在循环后对它们进行操作,我们可以避免多次对重复的选项进行操作。