我有一个包含值元组的 CSV 文件,我需要在不同的(大)文件中将一个值的出现次数更改为另一个值的出现次数。
到目前为止,我已经完成了一段时间的 read line [...] < foo.csv,实质上是为 CSV 文件中的每一行运行 sed 一次。
这需要相当长的时间,所以我想知道是否应该更改 while 循环来构造一个很长的多个 -e 语句字符串,然后使用 eval 运行它。
显然,我可以尝试,但如果有人可以告诉我 sed 本质上是否会执行与我迄今为止所做的相同的操作,即为每个 -e 语句运行文件,这意味着不会获得任何性能增益,那么我想我不会打扰。
评论后编辑:
基本上,我执行以下操作:
while read line
do
old_user=echo $line | cut -d \; -f 2|tr -d \"
new_user=echo $line | cut -d \; -f 4|tr -d \"
if [ "$old_user" != "$new_user" ]
then
sed -i -e "s/^(.*ri:username=\")$old_user(\".*)$/\1$new_user\2/g" confluence/entities_converted.xml
fi
done < usernames.csv
如果您注意到它是一个 XML 文件,原因是在很多情况下 XML 解析和重写很麻烦,因此sed
.我只是想知道,我是否应该构造多个参数,而不是sed
多次运行。-e
sed
usernames.csv
好像
"Full name";"Username";"Email";"New username"
"Sune Mølgaard";"sune.molgaard";"[email protected]";"smo"
沿着第二条线的路径可以有任意数量的线,因此是循环的。我知道第一行可能不匹配,但这无关紧要。
答案1
无需评估或构造多个 -e。 Sed 可以从文件或管道中读取其“程序”,您实际上也可以在 sed 中生成该“程序”:
cut -f2,4 -d\; usernames.csv \
| sed -e 's/^/s%ri:username=/' -e 's/;/%ri:username=/' -e 's/$/%/' \
| sed -i~ -f- confluence/entities_converted.xml
要检查生成的程序,请删除最后一行。
如果您想跳过不需要更改的行(可能会加快速度),请通过grep
在 sed 之间插入来删除它们:
| grep -v '"\(.*\)".*"\1"' \
答案2
您应该使用 awk 解析 usernames.csv (其中字段 2 和 4 不同),并生成 sed 文件。
tr -d \" username.csv |
awk -F\; '$2 != $4 { printf "s/^(.*ri:username=%c)%s(%c.*)$/\\1%s\\2/g\n",34,$2,34,$4 ; }' |
sed -i -f - confluence/entities_converted.xml
一些技巧
- 使用 printf "..%c..",34 生成引号。
- 您可以跳过调试部分中的 sed 行,以确保正确生成所有 sed 指令。
- 你需要
/g
替代吗?
在我的测试文件上
;foo;;foo;;
;fubar;;mr X;;
;bar;;bistro;;
"Full name";"Username";"Email";"New username"
"Sune Mølgaard";"sune.molgaard";"[email protected]";"smo"
这产生
s/^(.*ri:username=")fubar(".*)$/\1mr X\2/g
s/^(.*ri:username=")bar(".*)$/\1bistro\2/g
s/^(.*ri:username=")Username(".*)$/\1New username\2/g
s/^(.*ri:username=")sune.molgaard(".*)$/\1smo\2/g
不要费心删除用户名这一行,如果找不到,则无法替代。