>我有一个带有逗号分隔列的表,我想将指定列中的逗号分隔值分隔为新行。例如,给定的表是
Name Start Name2
A 1,2 X,a
B 5 Y,b
C 6,7,8 Z,c
我需要在第 2 列中分隔逗号分隔的值才能获得下表
Name Start Name2
A 1 X,a
A 2 X,a
B 5 Y,b
C 6 Z,c
C 7 Z,c
C 8 Z,c
我想知道是否有任何带有shell脚本的解决方案,以便我可以创建工作流管道。
注意:原始表格可能包含 3 列以上。
假设输入和输出的格式没有改变:
awk 'BEGIN{FS="[ ,]"} {print $1, $2, $NF; print $1, $3, $NF}' input_file
输入:
input_file
:
A 1,2 X
B 5,6 Y
输出:
A 1 X
A 2 X
B 5 Y
B 6 Y
解释:
-
awk
:调用awk
,一种用于操作行(记录)和字段的工具 -
'...'
: 用单引号括起来的内容作为说明提供给awk
-
'BEGIN{FS="[ ,]"}
:在阅读任何行之前,告诉awk同时使用空格和逗号作为分隔符;FS 代表 字段分隔符。 -
{print $1, $2, $NF; print $1, $3, $NF}
:对于读取的每个输入行,在一行上打印第一个、第二个和最后一个字段,然后在下一行打印第一个、第三个和最后一个字段。NF 代表字段数,因此$NF
是最后一个字段。 -
input_file
:提供输入文件的名称作为参数提供给awk。
响应更新的输入格式:
awk 'BEGIN{FS="[ ,]"} {print $1, $2, $4","$5; print $1, $3, $4","$5}' input_file
在 Runner 修改原始问题之后,另一种方法可能如下所示:
#!/bin/sh
# Usage $0 <file> <column>
#
FILE="${1}"
COL="${2}"
# tokens separated by linebreaks
IFS="
"
for LINE in `cat ${FILE}`; do
# get number of columns
COLS="`echo ${LINE} | awk '{print NF}'`"
# get actual field by COL, this contains the keys to be splitted into individual lines
# replace comma with newline to "reuse" newline field separator in IFS
KEYS="`echo ${LINE} | cut -d' ' -f${COL}-${COL} | tr ',' 'n'`"
COLB=$(( ${COL} - 1 ))
COLA=$(( ${COL} + 1 ))
# get text from columns before and after actual field
if [ ${COLB} -gt 0 ]; then
BEFORE="`echo ${LINE} | cut -d' ' -f1-${COLB}` "
else
BEFORE=""
fi
AFTER=" `echo ${LINE} | cut -d' ' -f${COLA}-`"
# echo "-A: $COLA ($AFTER) | B: $COLB ($BEFORE)-"
# iterate keys and re-build original line
for KEY in ${KEYS}; do
echo "${BEFORE}${KEY}${AFTER}"
done
done
使用此 shell 文件,您可以执行所需的操作。这会将第 2 列拆分为多行。
./script.sh input.txt 2
如果您想使用管道通过标准输入传递输入(例如,一次性拆分多列),您可以将 6. 行更改为:
if [ "${1}" == "-" ]; then
FILE="/dev/stdin"
else
FILE="${1}"
fi
并以此方式运行它:
./script.sh input.txt 1 | ./script.sh - 2 | ./script.sh - 3
请注意,切割对字段分隔符非常敏感。因此,如果该行以空格字符开头,则第 1 列将为 "(空)。如果字段由空格和制表符混合分隔,则此脚本也会出现其他问题。在这种情况下(如上所述),过滤输入资源(以便字段仅由一个空格字符分隔)应该这样做。如果这是不可能的,或者每列中的数据也包含空格字符,则脚本可能会变得更加复杂。