[已解决]awk求助:如何从字典文件逐行读取多列获值,并传递到sed查找替换另一个文件中的匹配行

sh/bash/dash/ksh/zsh等Shell脚本
回复
头像
careone
帖子: 839
注册时间: 2007-12-17 21:41

[已解决]awk求助:如何从字典文件逐行读取多列获值,并传递到sed查找替换另一个文件中的匹配行

#1

帖子 careone » 2014-09-18 23:01

awk求助:如何从字典文件逐行读取多列获值,并传递到sed查找替换另一个文件中的匹配行

2014-9-19更新:按4楼提供的方案,已成功解决。感谢各位的关心和热心帮助!
实现代码:

代码: 全选

awk -F',' 'NR==FNR{a[$4]=$2;next}{if(a[$4])$1=a[$4]}1' 001.dic 001.csv  >OK.csv
需求:

* 从 001.dic 字典文件中,提取2列数据: 第2列的“归类代码”,第4列的“搜索关键字”,然后依次在 CSV 源文件(001.csv)中,把符合指定关键字的行最前面的“未分类”,替换成字典文件中对应的“归类代码”。

* 另外还有一个类似的字典文件 002.dic, 或者还有更多其它字典文件,需要依次同样读取关键字,并对 001.csv 文件进行处理;

# 001.csv CSV表格文件
归类排序,排名,企业名称,国家
未分类,1,沃尔玛,美国
未分类,2,荷兰皇家壳牌石油公司,荷兰
未分类,3,中国石油化工集团公司,中国
未分类,4,中国石油天然气集团公司,中国

+++

# 001.dic 字典文件

代码: 全选

# coding: utf-8

	#!DICT_ID="sample-001"
	#!DICT_ENTERPRISE="JD(京东商城)"
	#!DICT_BRANCH="【上海浦西分拣中心】"

	#!DICT_VERSION="0.1"
	#!DICT_DATE="2014-08-30"
	#!DICT_DESC="sample dictionary for dlist"

	#ID,LINE_ID,LINE_NAME,KEY
	#0,LINE_9999,未分类,

	1,LINE_1001,线路1,中国
	2,LINE_1002,线路2,美国



* 最终完成后的 ok.csv 应该是这样的:
归类排序,排名,企业名称,国家
LINE_1002,1,沃尔玛,美国
未分类,2,荷兰皇家壳牌石油公司,荷兰
LINE_1001,3,中国石油化工集团公司,中国
LINE_1001,4,中国石油天然气集团公司,中国
主要程序代码如下:

代码: 全选

#!/bin/bash
	# coding: utf-8
	# filename: dlist.sh

	SRC=~/001.csv 
	SAVETO=~/ok.csv 

	DIC=~/001.dic

	cp $SRC $SAVETO

	clear

	declare -a DICS=( `ls -1 $HOME/*.dic` )
	for a in "${DICS[@]}"; do
	  echo "* dictionary: $a"

	echo
	# 查看处理前的原始CSV表格文件 001.csv
	echo "原始CSV表格文件: $SRC"
	echo " ------------"
	cat $SRC
	echo " ============"
	echo

	  if [ -z "$a" ]; then
	   continue;
	  else 
	    # grep -Ev '^#|^$' 的作用:不显示空白行,还有以#号开头的注释行
	    grep -Ev '^#|^$' "$a" | awk 'BEGIN { IFS="," ; UNSORT="未分类" ; SORT=$2 ; KEY=$4 } { sed "/$KEY/s/^$UNSORT/$SORT/" }' "$SAVETO"
	  fi
	  #echo
	done

	echo
	echo "处理后的文件: $SAVETO"
	# 查看处理后的文件 ok.csv
	echo "-------------"
	cat $SAVETO
	echo " ============"
	exit 0
运行以上代码,得到的 ok.csv 文件未收到预期效果( awk 相关参数似乎未起作用)。
请高手指点:应该怎样用 awk实现,或者用其它方式实现?

输出如下:

test@debian:~$ ~/bin/dlist.sh
* dictionary: /home/test/001.dic

原始CSV表格文件: /home/test/001.csv
------------
归类排序,排名,企业名称,国家
未分类,1,沃尔玛,美国
未分类,2,荷兰皇家壳牌石油公司,荷兰
未分类,3,中国石油化工集团公司,中国
未分类,4,中国石油天然气集团公司,中国
============


处理后的文件: /home/test/ok.csv
-------------
归类排序,排名,企业名称,国家
未分类,1,沃尔玛,美国
未分类,2,荷兰皇家壳牌石油公司,荷兰
未分类,3,中国石油化工集团公司,中国
未分类,4,中国石油天然气集团公司,中国
============
上次由 careone 在 2014-09-20 20:44,总共编辑 1 次。
魁拔不死,天下不宁。
魁拔既死,天下不平。
--------------
Careone <emacslocale^126.com>
https://sourceforge.net/projects/emacslocale/files/
poloshiao
论坛版主
帖子: 18279
注册时间: 2009-08-04 16:33

Re: awk求助:如何从字典文件逐行读取多列获值,并传递到sed查找替换另一个文件中的匹配行

#2

帖子 poloshiao » 2014-09-19 8:20

awk 相关参数似乎未起作用
檢查看看
sudo ls -al /usr/bin/awk
sudo ls -al /etc/alternatives/awk
man awk
头像
eexpress
帖子: 58428
注册时间: 2005-08-14 21:55
来自: 长沙

Re: awk求助:如何从字典文件逐行读取多列获值,并传递到sed查找替换另一个文件中的匹配行

#3

帖子 eexpress » 2014-09-19 9:26

用awk了,还传啥sed。
处理后的文件,没变化?
● 鸣学
cao627
帖子: 992
注册时间: 2007-12-05 10:57
系统: ubuntu14.04
来自: 金山

Re: awk求助:如何从字典文件逐行读取多列获值,并传递到sed查找替换另一个文件中的匹配行

#4

帖子 cao627 » 2014-09-19 10:49

感觉楼主写的过于复杂了。awk很强大的,下面一行代码作为参考

代码: 全选

$ awk -F',' 'NR==FNR{a[$4]=$2;next}{if(a[$4])$1=a[$4]}1' 001.dic 001.csv  >OK.csv
头像
careone
帖子: 839
注册时间: 2007-12-17 21:41

Re: awk求助:如何从字典文件逐行读取多列获值,并传递到sed查找替换另一个文件中的匹配行

#5

帖子 careone » 2014-09-20 20:29

感谢2,3楼的关注,以及4楼的热心帮助!

4楼的方案确认非常有效。

另:经过反复考虑,决定对字典文件的结构进行优化调整。即:

把原定义部分字段,单独另存为 001.dh 头文件, 并去除行首的注释符,
这样方便以脚本方式执行来获取变量定义。

新文件1(字典头文件):001.dh

代码: 全选

# coding: utf-8
# 2014-8-30 updated

DICT_ID="sample-001"
DICT_ENTERPRISE="JD(京东商城)"
DICT_BRANCH="【上海浦西分拣中心】"

DICT_VERSION="0.1"
DICT_DATE="2014-08-30"
DICT_DESC="dlist字典文件示例"
新文件2(提取后的字典字段): 001.dc1
优化后字典文件读取和提取数据更有效,对于处理大数据的 csv 源文件时,
性能会更好。

代码: 全选

LINE_1001,中国
LINE_1002,美国
LINE_1003,日本
LINE_1004,韩国
LINE_1005,德国
LINE_1006,法国
LINE_1007,英国

LINE_1008,俄罗斯
LINE_1009,荷兰
LINE_1010,印度
LINE_1011,瑞士

LINE_1021,银行
LINE_1022,保险
LINE_1023,石油
LINE_1024,能源
LINE_1025,电网
LINE_1026,电力
LINE_1027,汽车
LINE_1028,电信
LINE_1029,邮政
另程序会后续添加 新的“二级字典文件 001.dc2”,
即在 001.dc1 的基础上,再添加新的第二字段,运行时
只有在同一行同时匹配第2列和第3列的内容时,才把原文件的第一列替换为指定字典数据。

================
说明:
这个程序 dlist , 主要是为快递/物流人员,以及快递公司网点设计考虑。
主要目的是按地址片区,把订单自动分类、排序,再输出为可打印的 CSV 表格文件,
直接打印,减少人工筛选地址的工作量,提升物流行业的效率。

还可以把排序后的 CSV文件,导出为 mp3 的歌词文件格式(*.LRC)。
快递员在查看歌词文件时,先把歌曲暂停,这样就可以随意定位歌词的指定行和位置,
(对快递员来说,就是可以随时查看订单相关信息,方便安排自己送货线路,少走重复
路和回头路。还可以减少同一客户提货时多个订单只取走其中某一件的情况。

目前程序部分功能已实现,另有部分功能处于调试状态。等到代码稳定、调试通过后,
稍后会放出程序的 DEB 包,以及使用说明。
魁拔不死,天下不宁。
魁拔既死,天下不平。
--------------
Careone <emacslocale^126.com>
https://sourceforge.net/projects/emacslocale/files/
回复