在 CLI 上使用 'awk' 对文件内容执行 pre-check 并执行操作
Use 'awk' on CLI to do a pre-check on file contents and perform an action
我必须处理一个输入文件,如果它有超过 1 条记录(基本上是 header 以外的任何行)。
解析第一列和第三列以查看它是否具有字符串 "Test" 并排除这些行。
然后,将输出写入 - 最好再次写入同一个文件。
我在 SE 和 Google 上进行了搜索,认为这是非常接近的选择:
以及 Ed Morton 在同一主题上的评论。
我有它的部分工作,但需要把所有东西放在一起。
为了测试设置,我在输入文件中创建了 15 行。
$awk 'NR==FNR {next} FNR==1 {x=NR-1} { print x}' {filename.csv,filename.csv}
15
15
15
15
15
15
15
15
15
15
15
15
15
15
15
这是 x 能够保存行数的验证。
我希望,现在 x 持有 15,下面将处理我输入文件中的所有 15 行 - 但它似乎只处理了一行。
$awk 'NR==FNR {next} FNR==1 {x=NR-1} { if(x>1){print x;exit 0;}}' {filename.csv,filename.csv}
15
这是输入文件结构和预期输出。
before the process
filename.csv
col1,col2,col3,.....coln
test,xxx,test,.....
test,xxx,xxx,.....
xxx,xxx,test,.....
yyy,yyy,yyy,.....
zzz,zzz,zzz,.....
after the process
filename.csv
col1,col2,col3,.....coln
yyy,yyy,yyy,.....
zzz,zzz,zzz,.....
这部分执行我对 column1 和 column3 的检查
if ( !~ /[Tt][Ee][Ss][Tt]/ && !~ /[Tt][Ee][Ss][Tt]/) {print [=15=]} else exit 0}
P.S.
-1 文件将至少有 header 条记录。
-2 getline 不可用
-3 无法从 moreutils 安装 sponge 以重定向到同一文件。
-4 计划使用 tee 重定向到同一文件。
all of the code | tee filename.csv
从你的第一段和示例 input/output 看来,如果你想要一个完整的字符串匹配,这就是你所需要的:
$ awk -F, '(NR==1) || ((tolower() != "test") && (tolower() != "test"))' file.csv
col1,col2,col3,.....coln
yyy,yyy,yyy,.....
zzz,zzz,zzz,.....
如果您想要部分字符串匹配,则为:
awk -F, '(NR==1) || (!index(tolower(),"test") && !index(tolower(),"test"))' file.csv
如果您想要部分正则表达式匹配:
awk -F, '(NR==1) || ((tolower() !~ /test/) && (tolower() !~ /test/))' file.csv
最后,如果您想要完整的正则表达式匹配:
awk -F, '(NR==1) || ((tolower() !~ /^test$/) && (tolower() !~ /^test$/))' file.csv
抱歉,我不明白您发布的脚本或其余文本的意图。我认为您可能对 awk 的工作原理有严重的误解。获取 Effective Awk Programming,第 4 版,作者 Arnold Robbins。
如果你有 GNU awk 那么修改输入文件是:
awk -i inplace -F, '...' file.csv
和任何 awk:
awk -F, '...' file.csv > tmp && mv tmp file.csv
不要尝试将输出重定向到输入文件(包括通过管道中的其他命令),因为 shell 可能会在打开该文件作为输入读取之前对该文件进行处理以准备输出.
根据您的新要求,如果有匹配则只修改输入文件,请执行以下操作:
awk -F, '
NR==1 {hdr=[=16=] ORS}
.../3 test... {printf "%s", hdr; hdr=""; print}
END {exit (hdr=="" ? 0 : 1)}
' file.csv > tmp && mv tmp file.csv; rm -f tmp
我必须处理一个输入文件,如果它有超过 1 条记录(基本上是 header 以外的任何行)。
解析第一列和第三列以查看它是否具有字符串 "Test" 并排除这些行。
然后,将输出写入 - 最好再次写入同一个文件。
我在 SE 和 Google 上进行了搜索,认为这是非常接近的选择:
我有它的部分工作,但需要把所有东西放在一起。
为了测试设置,我在输入文件中创建了 15 行。
$awk 'NR==FNR {next} FNR==1 {x=NR-1} { print x}' {filename.csv,filename.csv}
15
15
15
15
15
15
15
15
15
15
15
15
15
15
15
这是 x 能够保存行数的验证。
我希望,现在 x 持有 15,下面将处理我输入文件中的所有 15 行 - 但它似乎只处理了一行。
$awk 'NR==FNR {next} FNR==1 {x=NR-1} { if(x>1){print x;exit 0;}}' {filename.csv,filename.csv}
15
这是输入文件结构和预期输出。
before the process
filename.csv
col1,col2,col3,.....coln
test,xxx,test,.....
test,xxx,xxx,.....
xxx,xxx,test,.....
yyy,yyy,yyy,.....
zzz,zzz,zzz,.....
after the process
filename.csv
col1,col2,col3,.....coln
yyy,yyy,yyy,.....
zzz,zzz,zzz,.....
这部分执行我对 column1 和 column3 的检查
if ( !~ /[Tt][Ee][Ss][Tt]/ && !~ /[Tt][Ee][Ss][Tt]/) {print [=15=]} else exit 0}
P.S.
-1 文件将至少有 header 条记录。
-2 getline 不可用
-3 无法从 moreutils 安装 sponge 以重定向到同一文件。
-4 计划使用 tee 重定向到同一文件。
all of the code | tee filename.csv
从你的第一段和示例 input/output 看来,如果你想要一个完整的字符串匹配,这就是你所需要的:
$ awk -F, '(NR==1) || ((tolower() != "test") && (tolower() != "test"))' file.csv
col1,col2,col3,.....coln
yyy,yyy,yyy,.....
zzz,zzz,zzz,.....
如果您想要部分字符串匹配,则为:
awk -F, '(NR==1) || (!index(tolower(),"test") && !index(tolower(),"test"))' file.csv
如果您想要部分正则表达式匹配:
awk -F, '(NR==1) || ((tolower() !~ /test/) && (tolower() !~ /test/))' file.csv
最后,如果您想要完整的正则表达式匹配:
awk -F, '(NR==1) || ((tolower() !~ /^test$/) && (tolower() !~ /^test$/))' file.csv
抱歉,我不明白您发布的脚本或其余文本的意图。我认为您可能对 awk 的工作原理有严重的误解。获取 Effective Awk Programming,第 4 版,作者 Arnold Robbins。
如果你有 GNU awk 那么修改输入文件是:
awk -i inplace -F, '...' file.csv
和任何 awk:
awk -F, '...' file.csv > tmp && mv tmp file.csv
不要尝试将输出重定向到输入文件(包括通过管道中的其他命令),因为 shell 可能会在打开该文件作为输入读取之前对该文件进行处理以准备输出.
根据您的新要求,如果有匹配则只修改输入文件,请执行以下操作:
awk -F, '
NR==1 {hdr=[=16=] ORS}
.../3 test... {printf "%s", hdr; hdr=""; print}
END {exit (hdr=="" ? 0 : 1)}
' file.csv > tmp && mv tmp file.csv; rm -f tmp