Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使用bash替换csv文件中特定位置的字符串_Bash_Awk_Sed_Cut - Fatal编程技术网

如何使用bash替换csv文件中特定位置的字符串

如何使用bash替换csv文件中特定位置的字符串,bash,awk,sed,cut,Bash,Awk,Sed,Cut,我有几个.csv文件,每个csv文件都有这样的行 AA,1,CC,1,EE AA,FF,6,7,8,9 BB,6,7,8,99,AA 我正在阅读每个csv文件的每一行,然后尝试将每一行的第四个位置以AA开头替换为ZZ 预期产量 AA,1,CC,ZZ,EE EE,FF,6,ZZ,8,9 BB,6,7,8,99,AA 然而,变量y确实分别包含第四个变量1和7,但是当我使用sed命令时,它会用ZZ替换第一个出现的1 如何修改代码以仅替换每行的第4个位置,而不考虑它的值 我的代码如下所示 $file

我有几个.csv文件,每个csv文件都有这样的行

AA,1,CC,1,EE
AA,FF,6,7,8,9
BB,6,7,8,99,AA
我正在阅读每个csv文件的每一行,然后尝试将每一行的第四个位置以AA开头替换为ZZ

预期产量

AA,1,CC,ZZ,EE
EE,FF,6,ZZ,8,9
BB,6,7,8,99,AA
然而,变量y确实分别包含第四个变量1和7,但是当我使用sed命令时,它会用ZZ替换第一个出现的1

如何修改代码以仅替换每行的第4个位置,而不考虑它的值

我的代码如下所示

$file=包含所有csv文件列表的文件名

for i in `cat file`
while IFS = read -r line;
do
if [[ $line == AA* ]] ; then
        y=$(echo "$line" | cut -d',' -f 4)
        sed -i "s/${y}/ZZ/" $i
fi
done < $i
编辑1:因为OP已经改变了要求,所以现在添加以下内容

awk 'BEGIN{FS=OFS=","} /^AA/||/^BB/{$4="ZZ"} /^CC/||/^DD/{$5="NEW_VALUE"} 1'  Input_file > temp_file && mv temp_file Input_file
你能试试下面的吗

awk -F, '/^AA/{$4="ZZ"} 1' OFS=,  Input_file > temp_file && mv temp_file Input_file

解释:现在也给上面的代码添加解释

awk '
BEGIN{              ##Starting BEGIN section of awk which will be executed before reading Input_file.
  FS=OFS=","        ##Setting field separator and output field separator as comma here for all lines of Input_file.
}                   ##Closing block for BEGIN section of this program.
/^AA/{              ##Checking condition if a line starts from string AA then do following.
  $4="ZZ"           ##Setting 4th field as ZZ string as per OP.
}                   ##Closing this condition block here.
1                   ##By mentioning 1 we are asking awk to print edited or non-edited line of Input_file.
'  Input_file       ##Mentioning Input_file name here.
编辑1:因为OP已经改变了要求,所以现在添加以下内容

awk 'BEGIN{FS=OFS=","} /^AA/||/^BB/{$4="ZZ"} /^CC/||/^DD/{$5="NEW_VALUE"} 1'  Input_file > temp_file && mv temp_file Input_file
你能试试下面的吗

awk -F, '/^AA/{$4="ZZ"} 1' OFS=,  Input_file > temp_file && mv temp_file Input_file

解释:现在也给上面的代码添加解释

awk '
BEGIN{              ##Starting BEGIN section of awk which will be executed before reading Input_file.
  FS=OFS=","        ##Setting field separator and output field separator as comma here for all lines of Input_file.
}                   ##Closing block for BEGIN section of this program.
/^AA/{              ##Checking condition if a line starts from string AA then do following.
  $4="ZZ"           ##Setting 4th field as ZZ string as per OP.
}                   ##Closing this condition block here.
1                   ##By mentioning 1 we are asking awk to print edited or non-edited line of Input_file.
'  Input_file       ##Mentioning Input_file name here.
使用sed:

使用sed:

使用sed,您还可以指示仅将逗号分隔值文件的第4个字段更改为ZZ,用于以AA开头的行:

解释

sed-我调用sed就地编辑文件; 一般形式/查找/匹配/替换/出现;哪里 查找是/^AA/以AA开头的行; 匹配[^,][^,]*一个字符,不是逗号,后跟任意数量的非逗号; 将第四次出现的匹配项/ZZ/4替换为ZZ。 注意,在这种情况下,awk和sed都提供了很好的解决方案,因此请参见和的答案

示例输入文件

示例使用/输出

注意:-我没有在下面使用,因此更改只是输出到标准输出

使用sed,您还可以指示仅将逗号分隔值文件的第4个字段更改为ZZ,用于以AA开头的行:

解释

sed-我调用sed就地编辑文件; 一般形式/查找/匹配/替换/出现;哪里 查找是/^AA/以AA开头的行; 匹配[^,][^,]*一个字符,不是逗号,后跟任意数量的非逗号; 将第四次出现的匹配项/ZZ/4替换为ZZ。 注意,在这种情况下,awk和sed都提供了很好的解决方案,因此请参见和的答案

示例输入文件

示例使用/输出

注意:-我没有在下面使用,因此更改只是输出到标准输出


要有力地做到这一点,只需:

$ awk 'BEGIN{FS=OFS=","} $1=="AA"{$4="ZZ"} 1' csv
AA,1,CC,ZZ,EE
AA,FF,6,ZZ,8,9
BB,6,7,8,99,AA
请注意,上面所做的是文字字符串比较和文字字符串替换,因此与目前发布的其他解决方案不同,如果本例中的目标字符串AA包含类似regexp的元字符,则不会失败。或者*,或者如果它可以是另一个字符串(如AAX)的一部分,或者如果此示例中的替换字符串ZZ包含反引用(如&or\1)

如果要在一次过程中映射多个字符串:

$ awk 'BEGIN{FS=OFS=","; m["AA"]="ZZ"; m["BB"]="FOO"} $1 in m{$4=m[$1]} 1' csv
AA,1,CC,ZZ,EE
AA,FF,6,ZZ,8,9
BB,6,7,FOO,99,AA
就像GNU sed使用-i进行就地编辑一样,GNU awk使用-i进行就地编辑,因此您可以放弃shell循环,只需执行以下操作:

awk -i inplace '
BEGIN { FS=OFS="," }
(NR==FNR) { ARGV[ARGC++]=$0 }
(NR!=FNR) && ($1=="AA") { $4="ZZ" }
{ print }
' file

它将在对awk的一次调用中对文件中命名的所有文件进行操作。最后一种情况下的文件是包含其他CSV文件名列表的文件。

要可靠地执行此操作,只需:

$ awk 'BEGIN{FS=OFS=","} $1=="AA"{$4="ZZ"} 1' csv
AA,1,CC,ZZ,EE
AA,FF,6,ZZ,8,9
BB,6,7,8,99,AA
请注意,上面所做的是文字字符串比较和文字字符串替换,因此与目前发布的其他解决方案不同,如果本例中的目标字符串AA包含类似regexp的元字符,则不会失败。或者*,或者如果它可以是另一个字符串(如AAX)的一部分,或者如果此示例中的替换字符串ZZ包含反引用(如&or\1)

如果要在一次过程中映射多个字符串:

$ awk 'BEGIN{FS=OFS=","; m["AA"]="ZZ"; m["BB"]="FOO"} $1 in m{$4=m[$1]} 1' csv
AA,1,CC,ZZ,EE
AA,FF,6,ZZ,8,9
BB,6,7,FOO,99,AA
就像GNU sed使用-i进行就地编辑一样,GNU awk使用-i进行就地编辑,因此您可以放弃shell循环,只需执行以下操作:

awk -i inplace '
BEGIN { FS=OFS="," }
(NR==FNR) { ARGV[ARGC++]=$0 }
(NR!=FNR) && ($1=="AA") { $4="ZZ" }
{ print }
' file

它将在对awk的一次调用中对文件中命名的所有文件进行操作。最后一种情况下的文件是包含其他CSV文件名列表的文件。

这应该替换上述代码中do之后的两行?我刚刚更新了我的问题:如果该行仅以AA开头,我想替换第四个字段,我将读取文件中的每一行,以检查它是否以AA开头。你能帮我查一下密码吗?谢谢你,一旦你添加了解释,我会试试看,并且一定会投赞成票。@shivaniarin,因此,有一种方法可以表达感谢:让我们也删除此答案下的所有注释,以保持答案干净。这应该替换上述代码中do之后的两行?我刚刚更新了我的问题:如果该行仅以AA开头,我想替换第四个字段,我将阅读文件中的每一行,以检查它是否正确是否以AA开头。你能帮我查一下密码吗?谢谢你,一旦你添加了解释,我会尝试一下,并且肯定会投赞成票。@Shivaniarin,所以有一种方式来表达感谢:让我们也删除这个答案下的所有评论,以保持答案的干净。这是一种相当罕见的鸟。几年前,我无意中发现了它,并将它添加到了我的工具箱中。它是
该应用程序是为.csv文件定制的,所以它不会受到太多的压力。哎呀,把狮子分到那里去吧。与替换csv中第四个位置的内容不同,我希望将其添加到第四个位置,并将较旧的第四个位置向右移动一个位置。你能帮我做这件事吗?是的,你可以通过简单的反向引用来做,例如。sed“/^AA/s/\[^,][^,]*\/ZZ、\1/4”文件会导致AA、1、CC、ZZ、1、EE等的第一行。注意:您捕获的文本介于“..”和插入ZZ后使用\1第一次反向引用重新插入该文本之间。很好。这很有效。但是你有没有详细的解释或者链接?我在网上找不到太多。这与答案中的解释相同,加上\…\它捕获了里面的文本,创建了对该文本的反向引用,允许您使用\1在替换部分重新插入该文本,如果您有第二个\…\则使用\2,依此类推。。。请看,您只是将第四个字段保存在\[^,][^,]*\中,然后将其替换为ZZ,\1-这将插入ZZ作为第四个字段,并将原始字段向右移动。这是一种非常罕见的鸟类。几年前,我无意中发现了它,并将它添加到了我的工具箱中。它的应用程序是为.csv文件定制的,所以它不会受到很大的压力。哎呀,把狮子分到那里去吧。与替换csv中第四个位置的内容不同,我希望将其添加到第四个位置,并将较旧的第四个位置向右移动一个位置。你能帮我做这件事吗?是的,你可以通过简单的反向引用来做,例如。sed“/^AA/s/\[^,][^,]*\/ZZ、\1/4”文件会导致AA、1、CC、ZZ、1、EE等的第一行。注意:您捕获的文本介于“..”和插入ZZ后使用\1第一次反向引用重新插入该文本之间。很好。这很有效。但是你有没有详细的解释或者链接?我在网上找不到太多。这与答案中的解释相同,加上\…\它捕获了里面的文本,创建了对该文本的反向引用,允许您使用\1在替换部分重新插入该文本,如果您有第二个\…\则使用\2,依此类推。。。请看,您只是将第四个字段保存在\[^,][^,]*\中,然后将其替换为ZZ,\1-这将插入ZZ作为第四个字段,并将原始字段向右移动。为什么第2行开头的AA变为EE?一次在一行上运行sed肯定是一种可怕的反模式。你想用一个进程处理整个文件,尤其是避免多次重写文件。为什么第2行开头的AA变成了EE?一次在一行上运行sed肯定是一种可怕的反模式。您希望用单个进程处理整个文件,尤其是避免多次重写文件。