我在文本文件中有以下行
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
第一次调用将csvformat
CSV 分隔符从|
逗号更改为逗号。然后可以通过简单调用 来删除文本中的管道(及其后面的空格)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
-|
不翻译(=删除)