将 CSV 值导入 Bash

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24762223/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 10:52:42  来源:igfitidea点击:

Import CSV value into Bash

linuxbashcsvawksed

提问by maihabunash

I have the following CSV file:

我有以下 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
.
.
.
.

My target is to set the CSV parameters ( all states in CSV ) with their values in my bash script

我的目标是在我的 bash 脚本中使用它们的值设置 CSV 参数(CSV 中的所有状态)

for example( regarding the second line values )

例如(关于第二行值)

in my bash script I will able to read each parameter

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

example

例子

 echo $Alabama
 1000 
 echo $Alaska
 1 0 0 1

First I just tried to write the following (wrong) code, in order to set the parameters with their values:

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

#!/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

The test should be (from the bash script)

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

echo $Alabama
1000

How should I change my code in order to implement my idea?

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

回答by Sylvain Leroux

Basic building block to solve your problem:

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

#!/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

Given your input file, this produces:

给定您的输入文件,这会产生:

sh$ ./m.sh 
Alabama
1000
100
10001


EDITIf you are only interested in the n-th line (stored in CSV_LINE), you could sed -n ...pyour input file (and use ifinstead of while):

编辑如果您只对第 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

Please note: since pipesare executed in a sub shell, the various variables are only bound insidethe body of the ifstatement.

请注意:由于管道子 shell中执行,因此各种变量仅绑定if语句主体内。



If you don't like the ifconstruct, I've just learned than using process substitution you might write:

如果你不喜欢这个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

Without a pipethere is not sub-shell -- so the variable are accessible from anywhere in the script after issuing the readinternal command.

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

回答by krisrose

Bash can handle CSV files like yours (there are some restrictions, more on that below) with a pattern like the following (assuming you run the script with the CSV file as standard input), which uses the field names in the first line as variable names automatically:

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

Your example could thus be encoded as

因此,您的示例可以编码为

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

which will print

这将打印

1000
100
10001
...

Notice, however, that using bash's read command with IFS=, in this way does not parse CSV files properly: bash only recognizes \-quoting but not the "-quoting that is usual in CSV files (as mandated, for example, by RFC4180).

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