
因此,我有一個充滿測試命令的文件,我喜歡對我的一些函數運行這些命令,以確保它們正確處理所有可能的情況。雖然有重複的命令是沒有意義的。以下是一些範例:
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
並在循環後對它們進行操作,我們可以避免多次對重複的選項進行操作。