使用awk将csv文件读入csh
Reading a csv file into csh using awk
假设我有一个名为 'list.txt' 的逗号分隔文件,其中包含以下内容:
1,fileA
2,fileB
我想在我的 csh 脚本中将它们读入一个 while 循环,这样我就可以分别操作逗号分隔的字段。我需要将其放大到输入文本文件中的任意行数,而不是本例中的 2 行。
#!/bin/csh
set j=1
while ($j <= 2)
set index = "`awk -F"," '{if (NR==$j) print }' list.txt`"
set file = "`awk -F"," '{if (NR==$j) print }' list.txt`"
echo $index
echo $file
@ j++
end
所以我希望它的输出是
1
fileA
2
fileB
但我得到的是:
1,fileA
1,fileA
2,fileB
2,fileB
我在这里错过了什么?如果我 运行 在我的 csh 脚本之外的终端中对任何给定行执行等效的 awk 命令,它会按我预期的那样工作。
awk -F"," '{if (NR==1) print }' list.txt
returns
1
我相信 csh 脚本的问题在于指定分隔符的双引号,这在 csh 中有其他含义,但我想不出解决方案。
不确定你的目标是什么,但你可以这样做:
tr ',' '\n' <file
1
fileA
2
fileB
试试,如果你感兴趣 awk
[akshay@localhost tmp]$ cat infile
1,fileA
2,fileB
[akshay@localhost tmp]$ awk -F, '{=}1' OFS="\n" infile
1
fileA
2
fileB
[akshay@localhost tmp]$ awk 'gsub(/,/,"\n")+1' infile
1
fileA
2
fileB
在这种情况下,解决方案是使用 cut
代替 awk
。
#!/bin/csh
foreach LINE ( `cat list.txt` )
set index = `echo "$LINE" | cut -d',' -f 1`
set file = `echo "$LINE" | cut -d',' -f 2`
echo $index
echo $file
end
产生所需的输出
1
fileA
2
fileB
并将字符串存储在变量中以供进一步使用。
以下是如何使用任何支持数组的 awk 和 shell 来完成您告诉我们的事情,例如bash:
$ awk -F, -v OFS='\n' '{=}1' file
1
fileA
2
fileB
$ IFS=$'\n' arr=( $(awk -F, -v OFS='\n' '{=}1' file) )
$ echo "${arr[0]}"
1
$ echo "${arr[1]}"
fileA
$ echo "${arr[2]}"
2
$ echo "${arr[3]}"
fileB
现在,如果您告诉我们您想对 awk 输出做什么,我们可以提供指导。
明确地说,上面的回声不是任何建议解决方案的一部分,它们只是为了显示数组已填充。如果你愿意的话,这在一个循环中是一样的(我在回声中添加了一些周围的 <
>
字符只是为了清楚地表明回声与 awk 在做什么):
$ cat tst.sh
IFS=$'\n' arr=( $(awk -F, -v OFS='\n' '{=}1' file) )
for i in "${arr[@]}"
do
echo "< $i >"
done
$ ./tst.sh
< 1 >
< fileA >
< 2 >
< fileB >
但尚不清楚这些是否有用。这更有可能是您想要的:
$ awk -F, -v OFS='\n' '{=}1' file | xargs -I {} -n1 echo "<" {} ">"
< 1 >
< fileA >
< 2 >
< fileB >
同样,在您向我们展示您要对输入文件的内容执行的操作之前,我们无法帮助您确定如何实施解决方案。
鉴于您刚才在评论中所说的想要 运行 一个名为 gausmooth
的命令,其参数包含从您的输入文件生成的文件名,这是一种方法(删除echo 执行命令而不是仅仅打印它):
$ cat tst.sh
awk -F, '{print }' file |
xargs -I {} echo gausmooth in="/home/Documents/{}" out="/home/Documents/gs_{}"
$ ./tst.sh
gausmooth in=/home/Documents/fileA1 out=/home/Documents/gs_fileA1
gausmooth in=/home/Documents/fileB2 out=/home/Documents/gs_fileB2
再说一次 - 如果这不是您想要的,请告诉我们故事的其余部分。
鉴于您的新需求,这可能就是您想要的:
$ cat file
fileA1,fileA2
fileB1,fileB2
$
$ while IFS=, read -r in1 in2
do
echo gausmooth in1="/home/Documents/$in1" in2="/home/Documents/$in2" out="/home/Documents/gs_${in1%%[0-9]*}"
done < file
gausmooth in1=/home/Documents/fileA1 in2=/home/Documents/fileA2 out=/home/Documents/gs_fileA
gausmooth in1=/home/Documents/fileB1 in2=/home/Documents/fileB2 out=/home/Documents/gs_fileB
正如我在另一条评论中提到的,通常的建议是一般避免 shell 循环,但我有时会在 simplicity/clarity 中使用它们,因为我可以控制输入并且很容易限制它所以这就是我在这种情况下所做的。假设 none 您的文件名包含逗号或换行符,并且可以通过从第一个 in
文件中删除尾随数字来创建 out
文件的名称。
假设我有一个名为 'list.txt' 的逗号分隔文件,其中包含以下内容:
1,fileA
2,fileB
我想在我的 csh 脚本中将它们读入一个 while 循环,这样我就可以分别操作逗号分隔的字段。我需要将其放大到输入文本文件中的任意行数,而不是本例中的 2 行。
#!/bin/csh
set j=1
while ($j <= 2)
set index = "`awk -F"," '{if (NR==$j) print }' list.txt`"
set file = "`awk -F"," '{if (NR==$j) print }' list.txt`"
echo $index
echo $file
@ j++
end
所以我希望它的输出是
1
fileA
2
fileB
但我得到的是:
1,fileA
1,fileA
2,fileB
2,fileB
我在这里错过了什么?如果我 运行 在我的 csh 脚本之外的终端中对任何给定行执行等效的 awk 命令,它会按我预期的那样工作。
awk -F"," '{if (NR==1) print }' list.txt
returns
1
我相信 csh 脚本的问题在于指定分隔符的双引号,这在 csh 中有其他含义,但我想不出解决方案。
不确定你的目标是什么,但你可以这样做:
tr ',' '\n' <file
1
fileA
2
fileB
试试,如果你感兴趣 awk
[akshay@localhost tmp]$ cat infile
1,fileA
2,fileB
[akshay@localhost tmp]$ awk -F, '{=}1' OFS="\n" infile
1
fileA
2
fileB
[akshay@localhost tmp]$ awk 'gsub(/,/,"\n")+1' infile
1
fileA
2
fileB
在这种情况下,解决方案是使用 cut
代替 awk
。
#!/bin/csh
foreach LINE ( `cat list.txt` )
set index = `echo "$LINE" | cut -d',' -f 1`
set file = `echo "$LINE" | cut -d',' -f 2`
echo $index
echo $file
end
产生所需的输出
1
fileA
2
fileB
并将字符串存储在变量中以供进一步使用。
以下是如何使用任何支持数组的 awk 和 shell 来完成您告诉我们的事情,例如bash:
$ awk -F, -v OFS='\n' '{=}1' file
1
fileA
2
fileB
$ IFS=$'\n' arr=( $(awk -F, -v OFS='\n' '{=}1' file) )
$ echo "${arr[0]}"
1
$ echo "${arr[1]}"
fileA
$ echo "${arr[2]}"
2
$ echo "${arr[3]}"
fileB
现在,如果您告诉我们您想对 awk 输出做什么,我们可以提供指导。
明确地说,上面的回声不是任何建议解决方案的一部分,它们只是为了显示数组已填充。如果你愿意的话,这在一个循环中是一样的(我在回声中添加了一些周围的 <
>
字符只是为了清楚地表明回声与 awk 在做什么):
$ cat tst.sh
IFS=$'\n' arr=( $(awk -F, -v OFS='\n' '{=}1' file) )
for i in "${arr[@]}"
do
echo "< $i >"
done
$ ./tst.sh
< 1 >
< fileA >
< 2 >
< fileB >
但尚不清楚这些是否有用。这更有可能是您想要的:
$ awk -F, -v OFS='\n' '{=}1' file | xargs -I {} -n1 echo "<" {} ">"
< 1 >
< fileA >
< 2 >
< fileB >
同样,在您向我们展示您要对输入文件的内容执行的操作之前,我们无法帮助您确定如何实施解决方案。
鉴于您刚才在评论中所说的想要 运行 一个名为 gausmooth
的命令,其参数包含从您的输入文件生成的文件名,这是一种方法(删除echo 执行命令而不是仅仅打印它):
$ cat tst.sh
awk -F, '{print }' file |
xargs -I {} echo gausmooth in="/home/Documents/{}" out="/home/Documents/gs_{}"
$ ./tst.sh
gausmooth in=/home/Documents/fileA1 out=/home/Documents/gs_fileA1
gausmooth in=/home/Documents/fileB2 out=/home/Documents/gs_fileB2
再说一次 - 如果这不是您想要的,请告诉我们故事的其余部分。
鉴于您的新需求,这可能就是您想要的:
$ cat file
fileA1,fileA2
fileB1,fileB2
$
$ while IFS=, read -r in1 in2
do
echo gausmooth in1="/home/Documents/$in1" in2="/home/Documents/$in2" out="/home/Documents/gs_${in1%%[0-9]*}"
done < file
gausmooth in1=/home/Documents/fileA1 in2=/home/Documents/fileA2 out=/home/Documents/gs_fileA
gausmooth in1=/home/Documents/fileB1 in2=/home/Documents/fileB2 out=/home/Documents/gs_fileB
正如我在另一条评论中提到的,通常的建议是一般避免 shell 循环,但我有时会在 simplicity/clarity 中使用它们,因为我可以控制输入并且很容易限制它所以这就是我在这种情况下所做的。假设 none 您的文件名包含逗号或换行符,并且可以通过从第一个 in
文件中删除尾随数字来创建 out
文件的名称。