스크립팅을 하다 보면 sort -V 옵션을 종종 사용해야 할 경우가 있습니다. 그런데 old OS 에 있는 sort 는 -V 옵션이 없는 경우가 있을 수 있습니다.
[root@host ~]# sort --help | grep -- "-V"
-V, --version-sort natural sort of (version) numbers within text
[root@host ~]#
sort -V 옵션이 필요한 경우는 대부분 다음과 같습니다.
cat << EOL | sort
1
2
10
20
EOL
위의 코드의 결과로는 보통은 1.. 2.. 10 .. 20 의 순서대로 나오기를 기대하게 됩니다. 하지만 위의 코드 결과는 실제
1
10
2
20
과 같이 의도하지 않는 출력이 되게 됩니다. 그러다 보니 어쩔수 없이 sort -V 를 구현을 해야 하게 됩니다.
아래 코드는 sort -V 옵션을 bash function 으로 만든 것입니다. license 는 BSD 2 clause 로 사용해 주시면 됩니다.
function sortv {
local var
local i
if [[ $# == 0 ]]; then
i=0
while read var_t
do
var[i++]="${var_t}"
done < /dev/stdin
else
var=( $* )
fi
(
for i in ${var[@]}
do
printf "ibase=2; %07d\n" "$(bc <<< "obase=2; ${i}")"
done
) | sort | bc
}
sort -V 2> /dev/null <<< "1"
[ $? -eq 0 ] && sort="sort -V" || sort="sortv"
cat <<EOL | ${sort}
1
10
2
20
EOL
출력 결과는
1
2
10
20
P.S.
기존의 sortv 함수가 문자열이나 공백이 들어갈 경우 문제가 되어 개선을 해 보았습니다.
function sortv {
local var
local i
if [[ $# == 0 ]]; then
i=0
while read var_t
do
var[i++]="${var_t}"
done < /dev/stdin
else
var=( $* )
fi
(
for i in "${var[@]}"
do
perl -p -e 's/([0-9]{4})/$1#~~#/g; s/([0-9]+)/`bc <<< "obase=2; $1" | xargs printf "%020d~~"`/eg' <<< "${i}"
done
) | sort | perl -pe 's/([0-9]{20})~~/`bc <<< "ibase=2; $1" | xargs printf "%s"`/eg; s/[0-9]{4}#~~#/$1/g'
}
sort -V 2> /dev/null <<< "1"
[ $? -eq 0 ] && sort="sort -V" || sort="sortv"
cat <<EOL | ${sort}
/home/0 asdfdsakf298u098uop;
/home/2 asdfdsakf298u097uop;
/home/5 asdfdsakf298u098uop;
/home/4 asdfdsakf298u098uop;
/home/11 asdfdsakf298u098uop;
/home/3 asdfdsakf298u028uop;
/home/1
EOL
출력 결과는
/home/0 asdfdsakf298u98uop;/home/1
/home/2 asdfdsakf298u97uop;
/home/3 asdfdsakf298u28uop;
/home/4 asdfdsakf298u98uop;
/home/5 asdfdsakf298u98uop;
/home/11 asdfdsakf298u98uop;