Shell:如何仅替换文件中双引号文本内的字符?

Shell:如何仅替换文件中双引号文本内的字符?

我在文本文件中有以下行

abc|45|"Do not replace | in this"|0.23

我想要一种仅替换|双引号文本中的字符的方法,结果

abc|45|"Do not replace in this"|0.23

我有大量的文件和行来进行此替换。无论如何我可以用 shell 脚本来实现它吗?

答案1

新答案(2022)使用磨坊主首先从无标头 CSV 输入的第三个字段中删除所有管道符号,然后折叠所有空格。引用内容均保留原文。

$ mlr --csv --fs pipe -N --quote-original put '$3 = collapse_whitespace(gsub($3,"[|]",""))' file
abc|45|"Do not replace in this"|0.23

同样的事情,但循环所有字段并尝试修改所有字符串:

$ mlr --csv --fs pipe -N --quote-original put 'for (k,v in $*) { is_string(v) { $[k] = collapse_whitespace(gsub(v,"[|]","")) } }' file
abc|45|"Do not replace in this"|0.23

将其应用于具有就地编辑功能的单个文件可以使用

mlr -I --csv ... *.csv

...确保这些文件已正确备份后。


旧答案(2019):

使用csvformat来自CSVKit, 和sed

$ csvformat -d '|' file | sed 's/| //' | csvformat -D '|'
abc|45|Do not replace in this|0.23

第一次调用将csvformatCSV 分隔符从|逗号更改为逗号。然后可以通过简单调用 来删除文本中的管道(及其后面的空格)sed。然后我们csvformat再次调用将分隔符更改回|

请注意,最终输出中不使用双引号。这是因为不再需要它们。它们一开始就不是实际数据的一部分,但只需要由于其中使用的管道来分隔该字段(原始数据是正确引用的 CSV 文件)。

您想要引用输出中的字段吗?请-U1与最终调用一起使用csvformat。这将引用所有字段。

答案2

您可以使用简单的替换来匹配以和sed开头的字符串"不是包含嵌入"并捕获该组,直到出现|,然后匹配从那里到结束的第二组"。只需打印出匹配的组,因为它们不包含该|字符

sed 's/\("[^"]*\).* |\([^"]*"\)/\1\2/g'

答案3

Ruby 有一个很好的 CSV 库,所以这可以是一句简单的话:

ruby -rcsv -e 'CSV.filter(col_sep: "|") {|row| row.each {|field| field.gsub!(/\| /, "")}}' file

答案4

使用 Perl(抱歉:混淆代码)

perl -pe 's/".*?"/ $& =~ tr[|][]dr /ge'     file

解释:

  • perl -pe proc- 适用proc于所有线路
  • s/RE/ f($&) /ge- 替换RE为结果 f(matching string)
  • tr[|][]dr -|不翻译(=删除)

相关内容