【问题标题】:Import CSV value into Bash将 CSV 值导入 Bash
【发布时间】:2014-07-15 15:28:36
【问题描述】:

我有以下 CSV 文件:

more my_file.csv
Alabama,Alaska,Arizona,Arkansas,California,Colorado,Connecticut,Delaware,Florida,Georgia,Hawaii,Idaho,Illinois,Indiana,Iowa
1000,"1 0 0 1",1002,1002,1003,1004,1005,"1 0 0 6",1007,1008,1009,1010,1011,1012,1013
100," 1 0 1 ",102,102,103,104,105,"1 0 6 2",107,108,109,"1 1 0 3 5 62 0",111,112,113
10001,10011,10021,10021,10031,10041,10051,10061,10071,10081,10091,10101,10111,10121,10131
.
.
.
.

我的目标是在我的 bash 脚本中设置 CSV 参数(CSV 中的所有状态)及其值

例如(关于第二行值)

在我的 bash 脚本中,我将能够读取每个参数

例子

 echo $Alabama
 1000 
 echo $Alaska
 1 0 0 1

首先我只是尝试编写以下(错误的)代码,以便设置参数及其值:

#!/bin/bash

counter=1

for CSV_COLUMN in Alabama  Alaska  Arizona Arkansas  California  Colorado  Connecticut Delaware Florida  Georgia  Hawaii  Idaho  Illinois  Indiana  Iowa 
do
  export $CSV_COLUMN=` echo $CSV_LINE | cut -d',' -f$counter `
  counter=$counter+1
done

测试应该是(来自 bash 脚本)

echo $Alabama
1000

我应该如何更改我的代码以实现我的想法?

【问题讨论】:

  • CSV 是一种表格格式。为什么echo $Alabama 应该只显示 first 行的字段值?
  • IN MY CASE --> 每个参数(CSV 中的第一行)都有一个值(值也可以在“......”之间)
  • 为什么要使用 csv 文件中的每一列值创建单独的 shell 变量。不会 awk 更适合处理 csv 文件。
  • 我心胸开阔,如果 awk 可以做得更好,请告诉我们? , awk 应该在 bash scipt 中(作为 awk 一行)

标签: linux bash csv awk sed


【解决方案1】:

解决您的问题的基本构建块:

#!/bin/bash

while IFS="," read Alabama  Alaska  Arizona Arkansas  California  Colorado  Connecticut Delaware Florida  Georgia  Hawaii  Idaho  Illinois  Indiana  Iowa 
do
    echo $Alabama
done < my_file.csv

根据您的输入文件,这会产生:

sh$ ./m.sh 
Alabama
1000
100
10001

编辑如果您只对第 n 行感兴趣(存储在CSV_LINE),您可以sed -n ...p 您的输入文件(并使用if 而不是while) :

#!/bin/bash

# ...
# Set your CSV_LINE to the (file) line number you are looking for (here, line 2)
CSV_LINE=2
# ...

sed -n "${CSV_LINE}p" | if IFS="," read Alabama  Alaska  Arizona Arkansas  California  Colorado  Connecticut Delaware Florida  Georgia  Hawaii  Idaho  Illinois  Indiana  Iowa 
then
    echo $Alabama
fi < my_file.csv

请注意:由于管道是在子shell中执行的,所以各种变量只绑定在if的主体内部声明。


如果您不喜欢 if 构造,我刚刚了解到您可能会写出使用进程替换:

#!/bin/bash

# ...
# Set your CSV_LINE to the (file) line number you are looking for (here, line 2)
CSV_LINE=2
# ...

IFS="," read Alabama  Alaska  Arizona Arkansas  California  Colorado  Connecticut Delaware Florida  Georgia  Hawaii  Idaho  Illinois  Indiana  Iowa \
       < <(sed -n "${CSV_LINE}p" < my_file.csv)

echo $Alabama

没有管道,就没有子shell——所以在发出read内部命令后,可以从脚本中的任何地方访问该变量。

【讨论】:

  • 是否可以这样做:完成
  • @maihabunash 我不太清楚$CSV_LINE 是什么。但无论如何,您当然可以从脚本内部重定向。假设它包含您的 CSV 文件的名称,类似于 ... done &lt; "$CSV_LINE"。正如我所说,这些只是基本的构建块。你现在应该可以自己进步了。如果您遇到其他问题,请随时提出其他问题!
  • CSV_LINE 是 CSV 文件中的一行(可以是第二行或第三行等)
  • @maihabunash 相应修改。
  • 是否可以从 CSV 重定向 $LINE ?如:完成
【解决方案2】:

Bash 可以处理像您这样的 CSV 文件(有一些限制,下面会详细介绍),其模式如下(假设您使用 CSV 文件作为标准输入运行脚本),它使用第一个中的字段名称行自动作为变量名:

# Get the field names from the first line
IFS=, read fields

# Define command to read all fields from a line
fieldsreader="IFS=, read ${fields//,/ }"

# Look over all records
while eval $fieldsreader; do
    ## This is run once per data line
    ## with access to $fieldname for all fields.
done

因此您的示例可以编码为

IFS=, read fields
fieldsreader="IFS=, read ${fields//,/ }"
while eval $fieldsreader; do
    echo $Alabama
done

将打印出来

1000
100
10001
...

但是请注意,使用带有 IFS= 的 bash 读取命令,以这种方式无法正确解析 CSV 文件:bash 仅识别 \-quoting 而不是 CSV 文件中常见的 "-quoting(如强制,例如, RFC4180)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-07-10
    • 1970-01-01
    • 2019-03-10
    • 2017-07-29
    • 1970-01-01
    • 2013-02-03
    • 2015-09-23
    相关资源
    最近更新 更多