Linux文本处理之awk、tr命令妙用:解析合并经纬度参数输出到终端窗口,方便一键复制
场景概述
场景:很多时候我们从数据源(数据库、文本文件、Excel表格等)取到经纬度数据,需要拿到其他地方查询或者使用,各个平台需要的参数格式可能大不相同,比如有的平台需要经度+纬度的格式,有的地方需要纬度+经度的格式(eg:Google地图搜索),复制的文本携带的分隔符也五花八门,手动用记事本类的软件过滤亦可达到目的,但比较繁琐,不够快捷,平日在终端工作的情况下,可以借助Bash脚本实现一键过滤和组合后输出,直接选中复制即可(mintty窗口下还可以直接双击鼠标左键进行当前行整行复制!)
下文使用lngandlat
函数实现同等目的,传递需要过滤和组合的经纬度参数即可;
优点:
- 传递的参数先后顺序不敏感,代码一定程度对参数进行判别:哪一个是经度,哪一个是纬度;
- 传递的参数格式较为宽松;分隔符数量不限,分隔符允许重叠,程序代码能对其进行智能缩减和过滤;
- 允许参数前或参数后包含多余的分隔符,分隔符支持常见特殊字符,支持分隔符夹分隔符的特殊情况处理;
- awk本身语法强大,允许后续增强和拓展其余功能;
借助tr、awk命令过滤分隔符,分隔字段域等,当前默认输出时以逗号作为分隔符;
函数 lngandlat
实现代码:
lngandlat() {
#经纬度格式转换,传入任意格式的经纬度数据,转换为需要的格式输出,方便一键复制
#经纬度参数可以分开传递也可以合在一个参数传递(lngandlat 111,222 与 lngandlat 111 222效果相同);
#支持 , # ;| || $ @ 等特殊符号作为经纬度分隔符,不限制分隔符字符数(重复无所谓),程序会自动缩减和处理
# 参数中包含井号(#)和分号(;)时,参数需要用双引号或单引号包裹,其他情况下,引号可以省去
# 注:awk没有内置求绝对值的函数,借用sqrt曲线救国;
# See Also:https://zhidao.baidu.com/question/1801649363884678947.html
# See Also2:https://zhidao.baidu.com/question/304949582658546204.html
# eg:
# lngandlat -102.995824 22.706189
# lngandlat -102.995824,22.706189
# lngandlat 22.706189,-102.995824,
# lngandlat ";;102.995824##22.706189"
# lngandlat ";;-102.995824##22.706189"
#------------------------------
_print_usage() { #打印帮助信息
echo -e "lngandlat:\n\t纬度格式转换,传入任意格式的经纬度数据,转换为多种或许需要的格式输出;"
echo -e "\t【目 的】:有的场景需要经度+纬度的组合,而有的需要纬度+经度组合,手动调换参数较为麻烦,故编写此快捷函数;"
echo -e "\t【快捷操作】:输出数据后,mintty窗口下可以双击鼠标左键复制当前行文本;"
echo -e "\t传入经纬度时先后顺序不敏感,分隔符可以为空格、逗号、#号或其他常见特殊字符,字符个数不限,程序会自动过滤处理;"
echo -e "\t经纬度参数可以分开传递也可以合在一个参数传递(\`lngandlat 111,222\` 与 \`lngandlat 111 222\` 效果相同);"
echo -e "\t注:参数数中包含井号(#)和分号(;)时,参数需要用双引号或单引号包裹,其他情况下,引号可以省去;"
echo -e "\nUsage:\n\tlngandlat *longitude~and~latitude~paramter\n"
echo -e "--------------------------------------------------------------"
echo -e "\nExample:\n\tlngandlat -102.995824 22.706189"
echo -e "\tlngandlat 22.706189 -102.995824 #参数顺序不敏感,经度可前可后"
echo -e "\tlngandlat -102.995824,22.706189 #两个参数可以合并传递"
echo -e "\tlngandlat 22.706189,-102.995824"
echo -e "\tlngandlat \"22.706189,,#,,-102.995824\" #分隔符字数不限"
echo -e "\tlngandlat \"-102.995824;22.706189\" #参数包含分号需加引号"
echo -e "\tlngandlat \"#102.995824##22.706189\" #参数可以包含任意特殊字符作为经度和纬度的分隔符,且分隔符个数不限"
echo -e "\tlngandlat \";;|\\\$-102.995824##22.706189\\$\\$\" #包含杂乱的分隔符不影响处理,注意包含\$需要转义"
echo -e "\tlngandlat ';;|\$-102.995824##22.706189\$\$' #使用单引号无需转义\$"
}
[ $# -eq 0 ] && echo -e "缺少参数!"
if [[ $# == 0 || "${*,,}" == "-h" || "${*,,}" == "--help" ]];then
_print_usage && return
fi
#这里借助awk统一在位置1输出经度,位置2输出纬度:
mapfile -t Coords <<<$(\
echo "$*"|tr -s ',;#|@$ '|awk -F '[,#;\\|\\$@ ]' '{
sub(/[^0-9]+?$/,""); /*替换参数结尾的分隔符,否则会影响栏位$NF定位*/
/*依次向前取到倒数第二个非空字段*/
/*为了处理分隔符夹分隔符的情况:lngandlat "22.706189,,#,,-102.995824"*/
findex=NF-1;
while($findex==""){
findex=findex-1;
}
previous=$findex;
if(previous<0 && $NF<90){ /*第一个数字小于零,第二个数字小于90,则认定为 经度、纬度格式*/
print previous;
print $NF;
}else if($NF<0 && previous<90) { /*第二个数字小于零,第一个数字小于90,则认定为 纬度、经度格式*/
print $NF;
print previous;
}else if(sqrt(previous*previous)>65 && sqrt($NF*$NF)>65) { /*两个数字绝对值过大,则认定为错误的经纬度数据(纬度最高为冰岛国的雷克雅未克:64°09′)*/
print "ERROR";
print "ERROR";
}else if(sqrt(previous*previous)<65 && sqrt($NF*$NF)>90) { /*对一个参数和第二个参数模糊求绝对值,推测为 纬度、经度格式*/
print $NF;
print previous;
}else if(sqrt($NF*$NF)<65) { /*对二个参数模糊求绝对值,默认情况认定为 经度、纬度格式*/
print previous;
print $NF;
}
/*此处不屏蔽错误,保留awk命令原始错误输出结果到屏幕终端,以便于查找原因!*/
/*复现报错提示可以使用:lngandlat "" */
}' 2>/dev/tty||echo -e "\033[41;37m输入数据解析有错误,请检查参数!\033[0m" >/dev/tty
)
[[ "${Coords[@]}" == "" ]] && return #有错误则直接退出!
local lng="${Coords[0]}" #经度
local lat="${Coords[1]}" #纬度
printf "原始数据:\n经度:%s\n纬度:%s\n\n" "$lng" "$lat"
printf "经纬度:\n%s,%s\n\n" $lng $lat
printf "纬经度:\n%s,%s\n\n" $lat $lng
#jq命令存在则同时输出格式化的JSON数据:
[ ! -z $(type -t jq) ] && printf '{"lng":"%s","lat":"%s"}' $lng $lat|jq '.'
}
使用帮助截图:
使用效果截图:
处理复杂分隔符的情况:
Gitee代码共享:
https://gitee.com/hexiyou/shell-scripts/blob/master/lngandlat.sh
本文来自博客园,作者:晴云孤魂,转载请注明原文链接:https://www.cnblogs.com/cnhack/p/16777980.html