在终端中使用 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
只是一个约定,它可以是任何有效的变量名,与col1
或var1
相同;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
我有一个问题来自
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
只是一个约定,它可以是任何有效的变量名,与col1
或var1
相同;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