在终端中使用 cut 或 awk 将两个单词字符串读取为单个字符串

reading two word strings as single string with cut or awk in terminal

我有一个问题来自 一个。我正在编写一个简单的 .ksh 文件以从 .csv 文件中读取单个列,然后将输出打印到屏幕上:

fname=($(sed 1d myfile.csv | cut -d, -f2))
# loop through these names
for i in ${fname[@]}; 
do echo "$i"
done

我现在遇到的问题是我希望 fname 中的每个条目都是一个字符串,可以是两个单词。例如,如果 csv 文件有一列

data
data 1
data 2

我希望 fname 是:

data
data 1
data 2

当前返回的位置:

data
data
1
data
2

是否可以调整我的代码来执行此操作?

我使用 awk 的一个版本是:

fname=($(awk -F "\"*,\"*" '{print }' "myfile"))
# loop through these names
for i in ${fname[@]}; 
do echo "$i"
done

awk 回答

$ cat myData
c1,data,c3
c1,data 1,c3
c1,data 2,c3

# demo-solution
awk -F, -v OFS=, '{print , "\""  "\"",  }' myDat

**output**

c1,"data",c3
c1,"data 1",c3
c1,"data 2",c3

如果您真的只需要第二个字段,只需从打印行中删除 ,, ,即

#exact output solution
awk -F, '{print "\""  "\"" }' myDat

**output**

"data"
"data 1"
"data 2"

这个答案也可以用于 "in-line" 从管道读取,例如

  youCSVproducingProcess | awk '......'

原始答案

echo "c1,data,c3
c1,data 1,c3
c1,data 2,c3" \
| while IFS=, read col1 col2 col3 ; do
echo "\"$col2\""
done

输出

"data"
"data 1"
"data 2"

是基本思路。

您可以创建一个脚本来处理文件

#!/bin/ksh
case $# in 0 ) echo "usage: myScript InputFile" ; exit 1 ;; esac
inFile=""
while IFS=, read col1 col2 col3 ; do
    echo "\"$col2\""
done < "$inFile"

此处的关键项目是 while ... done < "$inFile"IFS=,read col1 col2 col3

while 循环与 read var1 var2(或 read line)结合使用是一次读取文件 1 行的标准解决方案。请注意,这依赖于全部表示在 1 行上的数据标准。具有多列且列内有换行符的数据需要不同的方法。

read line只是一个约定,它可以是任何有效的变量名,与col1var1相同;my1Var也可以,还有很多其他的) .

为了使 read line 更有用,read 理解如果列出的变量超过 1 个 ('col1 col2 col3),它将采用标准输入(由 while 循环),然后读取该行数据,将其分解为 n 个字段。

read 的默认字段分隔符是 space-or-tab-char。 (在这里跳过一些细节,你们这些学究 ;-) )。使用 IFS=, 表示读取行并按 , 字符拆分字段。使用 2 个逗号,您将获得 3 个字段,如我的示例数据中所示。

我认为这可能是个问题。问题是您填充数组的方式:

fname=($(sed 1d myfile.csv | cut -d, -f2))

数组的元素是 "data"、"data"、“1”、"data"、“2”——您已经丢失了 "words"。

Bash 有一个很好的 mapfile 命令来读取文件或命令的输出并将行存储到数组中。对于 ksh,您可能需要做

fname=()
sed 1d myfile.csv | while IFS=, read -r col1 col2 rest; do
    fname+=( "$col2" )
done

请注意,在 for 循环中引用数组非常重要(我在回答另一个问题时确实提到了这一点):

for i in "${fname[@]}"; do
# .......^...........^ ............ quotes here are required
    echo "$i"
    # ...^..^ ..................... here too
done