我有一个具有以下格式的文件,每列由制表符分隔:
C1 C2 C3
a b,c d
e f,g,h i
j k l
...
现在我需要根据第二列中用逗号分隔的值的数量(如果是这种情况)来确定行数。这些行必须具有其中一个值,而不是其他值。结果将是这样的:
C1 C2 C3
a b d
a c d
e f i
e g i
e h i
j k l
...
...
由于这是由于尽快工作,我刚刚制作了一个不要在家执行此操作的脚本,用 逐行阅读while
,因为我缺乏相关技能awk
,或者没有使用其他工具探索其他可能的解决方案。脚本如下:
同时我正在修改剧本
# DON'T DO THIS AT HOME SCRIPT
> duplicados.txt
while IFS= read -r line; do
# get the value of the column of interest
cues="$(echo "$line" | awk -F'\t' '{ print $18 }')"
# if the column has commas then it has multiple values
if [[ "$cues" =~ , ]]; then
# count the commas
c=$(printf "%s" "$cues" | sed 's/[^,]*//g' | wc -c)
# loop according to the number of commas
for i in $(seq $(($c + 1))); do
# get each value of the column of interest according to the position
cue="$(echo "$cues" | awk -F',' -v c=$i '{ print $c; ++c }')"
# save the line to a file substituting the whole column for the value
echo "$line" | sed "s;$cues;$cue;" >> duplicados.txt
done
continue
fi
# save the single value lines
echo "$line" >> duplicados.txt
done < inmuebles.txt
有了这个,我得到了想要的结果(据我所知)。正如你可以想象的那样,脚本很慢而且效率很低。我怎么能用awk
或其他工具做到这一点?
真实数据的样本是这样的,感兴趣的列是数字 18:
1409233 UNION VIAMONTE Estatal Provincial DGEP 3321 VIAMONTE -33.7447365;-63.0997115 Rural Aglomerado 140273900 140273900-ESCUELA NICOLAS AVELLANEDA
1402961 UNION SAN MARCOS SUD Estatal Provincial DGEA, DGEI, DGEP 3029, 3311, Z11 SAN MARCOS SUD -32.629557;-62.483976 / -32.6302699949582;-62.4824499999125 / -32.632417;-62.484932 Urbano 140049404, 140164000, 140170100, 140173100 140049404-C.E.N.M.A. N° 201 ANEXO SEDE SAN MARCOS SUD, 140164000-C.E.N.P.A. N° 13 CASA DE LA CULTURA(DOC:BERSANO), 140170100-ESCUELA HIPOLITO BUCHARDO, 140173100-J.DE INF. HIPOLITO BUCHARDO
1402960 UNION SAN ANTONIO DE LITIN Estatal Provincial DGEA, DGEI, DGETyFP 3029, TZONAXI, Z11 SAN ANTONIO DE LITIN 3601300101020009 360102097366 0250347 SI / SI -32.212126;-62.635999 / -32.2122558;-62.6360432 / -32.2131931096409;-62.6291815804363 Rural Aglomerado 140049401, 140313000, 140313300, 140483400, 140499800 140049401-C.E.N.M.A. N° 201 ANEXO SAN ANTONIO DE LITIN, 140313000-I.P.E.A. Nº 214. MANUEL BELGRANO, 140313300-J.DE INF. PABLO A. PIZZURNO, 140483400-C.E.N.P.A. DE SAN ANTONIO DE LITIN, 140499800-C.E.N.P.A. B DE SAN ANTONIO DE LITIN
您可以
awk
通过拆分复合列,
并循环结果来做到这一点:也许更干净,你可以用Miller来做- 特别是使用nest 动词:
更紧凑
--explode --values --across-records --nested-fs ','
的可以替换为--evar ','
由于您还用 标记了问题
sed
,因此我感到敦促添加sed
解决方案:(注意:为了便于阅读,我使用
\n
了换行符和\t
制表符,就像您可以使用 GNU 一样sed
。对于可移植的解决方案,请使用带有实际换行符的反斜杠,而不是\n
实际的制表符\t
,输入ctrlV后跟tab)带逗号的行被复制到保留空间,一个副本打印逗号之前的内容,另一个副本使用逗号之后的部分进入下一个循环。详细地:
s//\n/
h
在我们弄乱线路之前保存一份到旧空间s/[^\t]*\n//
删除第一个逗号之前的部分x
改变缓冲区s/\n[^\t]*//p
删除从逗号开始的部分并打印它G
将保持空间附加到模式空间。这可以包含加法逗号,所以D
删除第一行(已打印的)并从该行的其余部分重新开始awk
(或perl
在awk
模式下)可能是最好的标准解决方案,但您可以在大多数 shell 中合理有效地执行此操作,尤其是那些带有数组 (ksh
,bash
,zsh
) 的 shell:对于没有数组的旧/有限外壳,请改用位置参数,例如(可能会有所不同):
使用 perl
perl
使用的选项:-perl
使用的内置变量:-Perl代码:-
在扩展正则表达式模式下使用GNU sed (-E):
这是记录 sed 正在做什么的进度操作:
使用位置参数数组使用 bourne shell 内置函数
输出