【问题标题】:Separate comma delimited cells to new rows with shell script使用 shell 脚本将逗号分隔的单元格分隔到新行
【发布时间】:2012-12-28 17:06:07
【问题描述】:

我有一个带有逗号分隔列的表,我想将指定列中的逗号分隔值分隔到新行。例如,给定的表是

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 列。

【问题讨论】:

  • When you tried自己解决这个问题,你遇到了什么问题?为什么是 Bash?
  • 我希望将输出通过管道传输到其他命令中,与在 R 中执行然后返回相比会节省一些时间。

标签: linux bash shell bioinformatics


【解决方案1】:

假设你的输入和输出的格式没有改变:

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

【讨论】:

  • 谢谢!我可以指定包含逗号分隔值的列吗?并且该表可能包含超过 3 列。
  • @Runner 你是什么意思?您能否在原始问题中提供一些用例作为编辑? (具体的例子很好,因为它可以帮助你定义问题的极端案例)
  • 非常感谢您的回答。现在我修改了我的问题。很抱歉造成混乱。
  • 我的错。我仍然没有提供一个很好的例子。我又修改了问题。
【解决方案2】:

在 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

注意 cut 对字段分隔符非常敏感。因此,如果该行以空格字符开头,则第 1 列将为“”(空)。如果字段由空格和制表符混合分隔,则此脚本也会有其他问题。在这种情况下(如上所述)过滤输入资源(以便字段仅由一个空格字符分隔)应该这样做。如果这是不可能的,或者每列中的数据也包含空格字符,则脚本可能会变得更加复杂。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-18
    • 1970-01-01
    相关资源
    最近更新 更多