【问题标题】:Loop through all columns in Bash遍历 Bash 中的所有列
【发布时间】:2016-10-23 17:03:11
【问题描述】:

我的目标是读取一个 .csv 文件,反转每一行,然后将结果写入另一个文件,我成功地做到了。

我的代码的问题是我必须指定 csv 文件中的列数(f1、f2、f3 等)。在我不知道 .csv 文件内容的情况下,如何在不指定列数的情况下使其遍历所有列?

PS:我确实在提问之前尝试在论坛上搜索过答案,但我真的找不到任何有用的东西!

input="/path/to/file"
while IFS=',' read -r f1 f2 f3 f4 f5 f6 f7
do 
    echo "$f7 $f6 $f5 $f4 $f3 $f2 $f1" >> output.csv
done < "$input"

【问题讨论】:

  • 小改进:在while循环外写&gt;&gt; output.csv

标签: bash csv


【解决方案1】:

使用 awk 不仅可以更轻松地处理可变数量的列,而且会更快

awk -F, '{ for(i=NF; i>=2; --i) printf "%s ", $i; print $1 }' "$input" > output.csv
  • -F, 告诉awk 用逗号将输入拆分为字段

  • for(i=NF; i&gt;= 2; --i) 循环遍历所有字段索引,从NF(输入字段的数量)倒计时到第二个字段。

  • $i 引用(从 1 开始)索引为 i 的字段(列)。

  • printf "%s " 是(隐式)循环体(为清楚起见,您可以将其括在{ ... } 中),它会使用尾随空格打印手头的字段,就像您的问题代码中一样。
    请注意,printfprint 不同,默认情况下不会自动附加换行符。

  • 最后,在循环之后,print $1 打印 first 字段,然后是换行符 (\n) 以完成输出行(\n 是默认值ORS,输出记录分隔符)。


如果您需要纯 Bash 解决方案慢得多):

Arrays 结合read -a 是解决方案:

while IFS= read -r line; do # read input line by line
  # Split line into fields and read into array.
  IFS=, read -ra fields <<<"$line"
  # Loop over fields from the back, down to the 2nd.
  for (( i = ${#fields[@]} - 1; i >= 1; --i )); do
    printf '%s ' "${fields[i]}"
  done
  # Print 1st field and complete line (append line).
  printf '%s\n' "${fields[0]}"
done < "$input" > output.csv

注意:

  • 单个输出重定向&gt; output.csv应用于整个循环(就像输入 重定向,&lt; "$input"),这比在循环中使用&gt;&gt; output.csv inside 更简单更高效(在后一种情况下,您还必须事先截断output.csv以确保没有附加任何预先存在的内容)。

  • bash 数组基于0,而基于awk 的数组从索引1 开始。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-10-19
    • 1970-01-01
    • 1970-01-01
    • 2022-11-18
    • 2020-03-09
    • 2018-12-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多