【问题标题】:In-line replacement bash (replace line with new one using variables)内联替换 bash(使用变量将行替换为新行)
【发布时间】:2013-09-27 02:27:30
【问题描述】:

我正在浏览并从文件中读取行。他们有大量不必要的信息,我想重新格式化这些行以供以后使用,以便以后可以使用必要的信息。

文件(file1)中的示例行

Name: *name* Date: *date* Age: *age* Gender: *gender* Score: *score*

假设我只想从文件中提取性别和年龄并稍后使用

换行

*gender*, *age*

在 bash 中:

    while read line; do
       <store variable for gender>
       <store variable for age>
     <overwrite each line in CSV - gender,age>
     <use gender/age as inputs for later comparisons>  
     done < file1

编辑:条目中没有稳定性。可以使用echo $line | cut 找到一个值,使用[ $line =~ "keyValue" ] 找到另一个值,然后设置该值

我正在考虑这样存储两个变量的组合:

newLine="$val1,$val2"

然后使用 sed 内联替换将 $line 替换为 $newLine

还有更好的方法吗?这可能归结为变量的 sed 格式问题。

【问题讨论】:

  • 条目的顺序是否稳定?是否保证所有条目都出现在每一行中?如果不能保证它们都出现,那么如何处理有年龄但没有性别或有性别但没有年龄的行?大概,既没有 Age 也没有 Gender 的行会被忽略?
  • “使用性别/年龄作为以后比较的输入”是什么意思?另外,介意在 CSV 文件中显示示例行吗?而且您不需要名称作为参考来替换目标性别/年龄吗? CSV 文件中的信息是否仅与一个人有关? namedate 这样的值确实有空格,对吗?附言使用 Ruby 处理 CSV 文件更容易。
  • *name*(或任何其他字段)可以包含空格吗?它可以包含冒号吗?您提到了 CSV,但我在您的输入中没有看到任何逗号 - 您发布的输入行真的代表您的实际输入吗?发布几行实际示例输入和预期输出。

标签: linux bash text sed awk


【解决方案1】:

您的示例为解释留下了空间,因此我假设字段值中可能有空格,但字段值中没有冒号,并且每个字段键后跟一个冒号。我也假设订单是稳定的。

while IFS=: read _ _ _ age gender _; do
    age="${age% Gender}" # Use parameter expansion to strip off the key for the *next* field.
    gender="${gender% Score}"
    printf '"%s","%s"\n' "$gender" "$age"
done < file1 > file1.csv

更新

由于您的问题现在表明没有稳定性,您必须遍历可能的值以获得输出:

while IFS=: read -a line; do
    unset age key sex
    for chunk in "${line[@]}"; do
        val="${chunk% *}" # Everything but the key
        case "$key" in
            Age) age="$val";;
            Gender) sex="$val";;
        esac
        # The key is for the *next* iteration.
        key="${chunk##* }"
    done
    if [[ $age || $sex ]]; then
        printf '"%s","%s"\n' "$sex" "$age"
    fi
done < file1 > file1.csv

(此外,我在 csv 中的输出值周围添加了引号,以符合实际的 csv 格式,以防性别或年龄恰好有逗号。也许有人有 1,000,000 岁。;)

【讨论】:

  • 好悲痛。这就是为什么你不使用 shell 来解析文本文件的原因——使用正确的工具来完成这项工作,即 awk。
  • @EdMorton 您想建议我可以应用的实际改进吗? Shell 通常是一种重新格式化文本的出色方法,因此我反对您未明确提出的反对意见。
  • 我确实提出了改进建议 - 使用为操作文本而发明的工具,具有简化文本操作所需的所有内置结构,并且可用于所有 UNIX 安装,即 awk。不知道我还能做些什么来更具体。
  • @EdMorton 大多数情况下,您的评论只是挥舞着 awk 的旗帜,但这不是必需的,因为您的答案应该是独立的。如果您指出您认为我的解决方案有什么问题,您的评论可能更具建设性,它举例说明了为什么您不应该使用 shell 来解析文本文件。
  • 我认为这些问题是不言而喻的。如果没有,我道歉。以下是使用 shell 脚本解析文本文件的一些常见问题,这些问题由该脚本举例说明:它冗长、复杂,并且与输入数据耦合(请参阅在 shell 中使用特定的“键”值作为变量和案例)脚本)。
【解决方案2】:

这将从您发布的示例输入中产生您想要的输出:

$ cat file
Name: *name* Date: *date* Age: *age* Gender: *gender* Score: *score*

$ awk -F'[: ]+' -v OFS=', ' '{for (i=1;i<NF;i+=2) a[$i]=$(i+1); print a["Gender"], a["Age"]}' file
*gender*, *age*

$ awk -F'[: ]+' -v OFS=', ' '{for (i=1;i<NF;i+=2) a[$i]=$(i+1); print a["Score"], a["Name"], a["Date"] }' file
*score*, *name*, *date*

您可以在上面看到以您喜欢的顺序打印您喜欢的任何字段是多么容易。

如果不是您想要的,请发表一些更具代表性的意见。

【讨论】:

    猜你喜欢
    • 2011-11-05
    • 1970-01-01
    • 2015-11-10
    • 2016-12-02
    • 2018-11-04
    • 2011-12-02
    • 2021-11-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多