如何添加 if-else 条件来定义 gawk、ksh 中的字段分隔符?
How can I add if-else condition to define the field separator in gawk, ksh?
我必须处理管道分隔文件中的一些数据,其中每个字段都用双引号引起来。
"Boolean"|"dada -sdf|xcvnb"|"123"
如果我取FS="|"
,那么脚本将上面的作为四个字段,而实际上是三个字段。如果我选择 FS="\"|\""
那么我有两个问题:
- 我必须分别处理第一个和最后一个字段
"Boolean
和 123"
- 更重要的是,由于我们不再使用双引号,当我获取每个字段和过程时,某些函数或命令可能不会获取字段中的整个字符串(因为它们可能被分开通过 spaces 和不同的其他字符)。例如第二个字段变为
dada -sdf|xcvnb
即没有引号,对于某些命令可能会给出错误的结果,因为 -
可能被解释为选项,或者只有第一个单词可能被视为参数和 [ 之后的字符串的其余部分=34=]根本没有考虑。
我的想法 - 我想告诉 gawk 只有当它后面跟着一个 "
并且前面有一个 "
时才把 FS 当作 |
。这样我就不会去掉字段中的双引号。
如何编写代码?有办法吗?
使用 gawk
,您可以使用 FPAT
变量来定义字段的外观模式。在您的情况下,字段由 "
后跟零个或多个任意字符组成, "
和最后一个 "
.
有了这个你可以简单地打印第一个字段 </code> 和最后一个字段 <code>$NF
:
gawk '{print ,$NF}' FPAT='"[^"]*"' OFS="|" \
<<< '"Boolean"|"dada -sdf|xcvnb"|"123"'
输出:
"Boolean"|"123"
I want to tell gawk that take FS as | only if it is followed by a " and preceded by a "
您可以在 perl
中通过积极的前瞻和后视来做到这一点...
$ perl -F'/"\K\|(?=")/' -le 'print "$F[0] : $F[1] : $F[2]"' ip.txt
"Boolean" : "dada -sdf|xcvnb" : "123"
-F
指定字段分隔符并保存在@F
数组中
- 还设置了
-n
标志,这意味着在循环中迭代输入文件,默认情况下不打印行
- 要按空格拆分,可以简单地使用
-a
选项
'/"\K\|(?=")/'
使用正则表达式指定字段分隔符。 "\K
是积极的后视,(?=")
是积极的前瞻。 \|
为分隔符(|
需要转义)
-l
从输入行中去除换行符并将换行符添加到 print
语句
-e
允许直接传递 perl
代码而不是从文件
$F[0]
数组索引以0
开头,这个指的是@F
数组的第一个元素
进一步阅读:
- Perl flags -pe, -pi, -p, -w, -d, -i, -t?
- perl command switches
我会使用真正的 CSV 解析器。我喜欢 ruby 的:
ruby -rcsv -e '
opts = { :col_sep => "|", :force_quotes => true }
CSV.parse(STDIN.read, opts) do |row|
row.delete_at(1)
puts row.to_csv(opts)
end
' filename
产出
"Boolean"|"123"
我必须处理管道分隔文件中的一些数据,其中每个字段都用双引号引起来。
"Boolean"|"dada -sdf|xcvnb"|"123"
如果我取FS="|"
,那么脚本将上面的作为四个字段,而实际上是三个字段。如果我选择 FS="\"|\""
那么我有两个问题:
- 我必须分别处理第一个和最后一个字段
"Boolean
和123"
- 更重要的是,由于我们不再使用双引号,当我获取每个字段和过程时,某些函数或命令可能不会获取字段中的整个字符串(因为它们可能被分开通过 spaces 和不同的其他字符)。例如第二个字段变为
dada -sdf|xcvnb
即没有引号,对于某些命令可能会给出错误的结果,因为-
可能被解释为选项,或者只有第一个单词可能被视为参数和 [ 之后的字符串的其余部分=34=]根本没有考虑。
我的想法 - 我想告诉 gawk 只有当它后面跟着一个 "
并且前面有一个 "
时才把 FS 当作 |
。这样我就不会去掉字段中的双引号。
如何编写代码?有办法吗?
使用 gawk
,您可以使用 FPAT
变量来定义字段的外观模式。在您的情况下,字段由 "
后跟零个或多个任意字符组成, "
和最后一个 "
.
有了这个你可以简单地打印第一个字段 </code> 和最后一个字段 <code>$NF
:
gawk '{print ,$NF}' FPAT='"[^"]*"' OFS="|" \
<<< '"Boolean"|"dada -sdf|xcvnb"|"123"'
输出:
"Boolean"|"123"
I want to tell gawk that take FS as | only if it is followed by a " and preceded by a "
您可以在 perl
中通过积极的前瞻和后视来做到这一点...
$ perl -F'/"\K\|(?=")/' -le 'print "$F[0] : $F[1] : $F[2]"' ip.txt
"Boolean" : "dada -sdf|xcvnb" : "123"
-F
指定字段分隔符并保存在@F
数组中- 还设置了
-n
标志,这意味着在循环中迭代输入文件,默认情况下不打印行 - 要按空格拆分,可以简单地使用
-a
选项
- 还设置了
'/"\K\|(?=")/'
使用正则表达式指定字段分隔符。"\K
是积极的后视,(?=")
是积极的前瞻。\|
为分隔符(|
需要转义)-l
从输入行中去除换行符并将换行符添加到print
语句-e
允许直接传递perl
代码而不是从文件$F[0]
数组索引以0
开头,这个指的是@F
数组的第一个元素
进一步阅读:
- Perl flags -pe, -pi, -p, -w, -d, -i, -t?
- perl command switches
我会使用真正的 CSV 解析器。我喜欢 ruby 的:
ruby -rcsv -e '
opts = { :col_sep => "|", :force_quotes => true }
CSV.parse(STDIN.read, opts) do |row|
row.delete_at(1)
puts row.to_csv(opts)
end
' filename
产出
"Boolean"|"123"