我有一个巨大的文件(超过 2 GB),其中数据如下所示。
12,324,32342,E:fsdsf,23432,34534,45345,324
13,3224,342,E:werwefsdsf,23432,34534,45345,324
121,3244,33442,E:,23432,34534,45345,324
在这里,我需要替换第四列中所有遇到E:
空格的地方""
,但无论它在后面找到字符串E:
,都应该保持原样。
预期输出为:
12,324,32342,E:fsdsf,23432,34534,45345,324
13,3224,342,E:werwefsdsf,23432,34534,45345,324
121,3244,33442,,23432,34534,45345,324
答案1
你的语法是几乎正确的。要测试 中的字符串相等性awk
,请使用双等号:==
。到指定一个值,使用单个等号。
所以使用if ($4 == "E:")
你应该会得到你想要的结果。
完整的命令如下所示。请注意,与您使用的命令只有一个字符不同;这是你唯一的错误:
awk -F , '{ if ($4 == "E:") $4="";}1' OFS=, data.final
为了展示一些不同的语法和不同的方法,以下版本是完全等效的:
awk -F, -v OFS=, '$4 == "E:" { $4 = "" }; 1' data.final
awk 'BEGIN { FS=OFS="," }; $4 == "E:" { $4 = "" }; {print}' data.final
awk -F, -v OFS=, '{sub( /^E:$/, "", $4); print}' data.final
关于上述事项的注意事项:
- 如果您的整个代码块只是一个 if/then,您可以仅使用条件作为代码块的过滤器。因此
$4 == "E:" {$4 = ""}
完全等同于{if ($4 == "E:") {$4 = ""}}
- 将“then”语句括在代码块中是一种很好的做法,即使只有其中一个语句,即
if ($4 == "E:") {$4 = ""}
而不是if ($4 == "E:") $4 = "";
-F
设置的值FS
,并可-v
用于在awk
考虑第一个文件的第一行之前设置任何变量的值。(您可能知道这一点。)您也可以使用块BEGIN
来做同样的事情;当您想让脚本awk
独立时,值得了解这一点。1
打印行 in 的原因是它是一个始终评估为 true 的条件(过滤器),并且当没有代码块附加到过滤器时的awk
默认操作是 to 。所以它本身就相当于or或者 只是。awk
print $0
1
1 {print}
1 {print $0}
{print}
- 在我的最后一个变体中,我使用一个函数将正则表达式(字符串开头、字符串结尾)
sub
替换为in 。/^E:$/
E:
""
$4
由于该sub
函数返回进行的替换数(1 或 0;用于gsub
进行多个替换),因此您可以通过在sub
函数结果中添加 1 来解决此问题,以确保您拥有始终为真的模式,因此无论是否进行替换,都会打印结果行。这是高尔夫版本的代码,如果您将其放入随后要维护的脚本中,则不建议初学者使用:
awk -F, -v OFS=, 'sub(/^E:$/,"",$4)+1' data.final
:)
答案2
和sed
:
sed -r 's/^([^,]+,[^,]+,[^ ]+,)E:(,)/\1\2/' file.txt
如果第四个逗号分隔字段仅包含 ,则该字段将为空白E:
。
例子:
% cat file.txt
12,324,32342,E:fsdsf,23432,34534,45345,324
13,3224,342,E:werwefsdsf,23432,34534,45345,324
121,3244,33442,E:,23432,34534,45345,324
% sed -r 's/^([^,]+,[^,]+,[^ ]+,)E:(,)/\1\2/' file.txt
12,324,32342,E:fsdsf,23432,34534,45345,324
13,3224,342,E:werwefsdsf,23432,34534,45345,324
121,3244,33442,,23432,34534,45345,324
答案3
假设您的文件名为file
,您可以尝试以下操作:
while read -r line;
do
var="$(echo "$line" | cut -d ',' -f 4)";
if [[ "$var" = "E:" ]]; then echo "$line" | sed s/"$var"/''/g ;
else echo "$line";
fi;
done < file
或者:
while read -r line; do var="$(echo "$line" | cut -d ',' -f 4)"; if [[ "$var" = "E:" ]]; then echo "$line" | sed s/"$var"/''/g ; else echo "$line";fi; done < file
解释:
while read -r line;
逐行读取文件var="$(echo "$line" | cut -d ',' -f 4)";
将第 4 个位置的字符串分隔,
成变量var
if [[ && "$var" = "E:" ]]; then echo "$line" | sed s/"$var"/' '/g ;
如果$var
恰好有字符串E:
则将sed s/"$var"/''/g ;
其替换为空白""
else echo "$line";
否则它会按原样打印行
例子输出(正如问题所预期的那样):
file
:$ cat file 12,324,32342,E:fsdsf,23432,34534,45345,324 13,3224,342,E:werwefsdsf,23432,34534,45345,324 121,3244,33442,E:,23432,34534,45345,324
运行命令:
$ while read -r line; do var="$(echo "$line" | cut -d ',' -f 4)"; if [[ "$var" = "E:" ]]; then echo "$line" |sed s/"$var"/' '/g ; else echo "$line";fi; done < file 12,324,32342,E:fsdsf,23432,34534,45345,324 13,3224,342,E:werwefsdsf,23432,34534,45345,324 121,3244,33442,,23432,34534,45345,324
>> file2
您还可以使用或|tee file2
在命令的最后将输出重定向到文件:
while read -r line; do var="$(echo "$line" | cut -d ',' -f 4)"; if [[ "$var" = "E:" ]]; then echo "$line" |sed s/"$var"/' '/g ; else echo "$line";fi; done < file | tee file2