【问题标题】:sed replace text between commased 替换逗号之间的文本
【发布时间】:2020-02-20 08:58:33
【问题描述】:

我有 csv 文件需要更改 f -> 0 和 t -> 1 仅在每个 csv 的逗号之间(如果匹配)。来自:

,t,t,f,f,a,t,f,t,f,f,t,f,
tftf

到:

,1,1,0,0,a,1,0,1,0,0,1,0,
tftf

以这种方式工作,但想知道可以减少更换时间消耗的更好方法

for i in 1 2 3 4 5 6
do
  echo "converting tables for mariaDB"
  find ./ -type f -name "*.csv" -print0 | xargs -0 sed -i 's/\,t\,/\,1\,/g'
  find ./ -type f -name "*.csv" -print0 | xargs -0 sed -i 's/\,f\,/\,0\,/g'
  echo "$i time(s) changed "
done

我除外,一个命令将改变行

【问题讨论】:

  • 不确定你为什么在这里使用 for 循环。你不需要在 sed 命令中转义,,你可以同时使用多个命令......而且你不需要xargs...如果您的find 不支持+,请尝试find ./ -type f -name "*.csv" -exec sed -i 's/,t,/,1,/g; s/,f,/,0,/g' {} + 使用\;
  • 我建议使用sed 两个循环:':1;s/,t,/,1,/g;t1; :2;s/,f,/,0,/g;t2'
  • @Cyrus 哦,我现在明白了为什么 OP 使用了循环......很棒的观察
  • 可以在这里使用perl ... perl -i -pe 's/,\Kt(?=,)/1/g; s/,\Kf(?=,)/0/g'
  • 可以肯定的是,只有逗号之间?像这样的行呢:t,t,f

标签: awk sed replace


【解决方案1】:

请您尝试以下操作。虽然它不是完美的解决方案,但如果您没有 gawk 的最新版本(其中存在 -inplace 编辑选项),那么使用它是最简单的。

for file in *.csv
  awk '{gsub(/,t,/,",1,");gsub(/,f,/,",0,");gsub(/,t,/,",1,");gsub(/,f,/,",0,")} 1' "$file" > temp && mv temp"$file"
done

for file in *.csv
    awk -v t_val="1" -v f_val="0" 'BEGIN{FS=OFS=","}{for(i=2;i<NF;i++){$i=($i=="t"?t_val:$i=="f"?f_val:$i)}} 1' "$file" > temp && mv temp "$file"
done


第二个解决方案:使用gawk的最新版本,我们可以将编辑保存到 Input_file 本身。

gawk -i inplace '{gsub(/,t,/,",1,");gsub(/,f,/,",0,");gsub(/,t,/,",1,");gsub(/,f,/,",0,")} 1' *.csv

gawk -i inplace -v t_val="1" -v f_val="0" 'BEGIN{FS=OFS=","}{for(i=2;i<NF;i++){$i=($i=="t"?t_val:$i=="f"?f_val:$i)}} 1' Input_file

【讨论】:

  • 这里的问题是看起来像,t,t,t,t, 的行不会转换所有tgsub 不会重叠。
  • 为什么不像BEGIN { FS = OFS = "," } { for (i = 2; i &lt; NF; i++) $i = ($i == "t" ? 1 : $i == "f" ? 0 : $i) } 1这样的?我的意思是这比目前给出的答案更尴尬和更快,除了 sed w 两个循环
  • @oguzismail 我在第一个答案中写下了那个。这很好用,但如果你有很多字段,它会很慢。它缓慢的原因是您每次都重新定义一个字段,因此,您重新计算 $0 并一遍又一遍地将其拆分为字段。一种更快的方法是将$0 存储在tmp 中。使用split,处理数组并使用printf 重建数组。但是,我总是觉得很遗憾awk 没有与split 相反的merge 命令。
  • @oguzismail,谢谢哥们,我已经在我的解决方案或帖子中添加了该解决方案,如果有任何建议或编辑请告诉我。
  • 双重gsub 显然更快。我对“字段”更新进行了更新,这将避免重新计算 $0 和自动“字段拆分”
【解决方案2】:

在这种情况下,主要问题是正则表达式在使用sed 's/ere/str/g'awk '{gsub(ere,str,$0)}' 解析时不允许重叠。 This comment 很好地解释了如何在 sed 中使用 t&lt;label&gt; 命令规避此问题,这意味着:如果模式空间发生变化,请移至 注释显示通用的方法。此规则的 awk 替代方案是:

$ awk '{while(match($0,ere)) gsub(ere,str)}'

在 OP 示例的情况下,另一种 sed 解决方案可以使用以下想法:

  1. 复制所有逗号。由于我们正在搜索“,t”形式的字符串,因此这种重复使用s 避免了重叠。
  2. 由于不可能重叠,请将所有“,f”替换为“,0”,并将所有“,t”替换为“,1”。
  3. 我们现在可以再次恢复所有重复的逗号。由于不允许重叠,像,,,, 这样的序列将很好地转换为,, 而不是,

在 POSIX sed 中,这看起来像:

$ sed -e 's/,/,,/g' -e 's/,f,/,0,/g' \
      -e 's/,t,/,1,/g' -e 's/,,/,/g' file > file.tmp
$ mv file.tmp file

使用 GNU sed,我们可以一次性完成:

$ sed -i 's/,/,,/g;s/,f,/,0,/g;s/,t,/,1,/g;s/,,/,/g' file

使用 awk,它看起来像:

$ awk 'BEGIN{FS=",";OFS=FS FS}
       {$1=$1;gsub(/,f,/,",0,");gsub(/,t,/,",1,");gsub(OFS,FS)}1' file > file.tmp
$ mv file.tmp file

【讨论】:

    猜你喜欢
    • 2018-05-14
    • 1970-01-01
    • 1970-01-01
    • 2019-05-02
    • 1970-01-01
    • 1970-01-01
    • 2012-12-07
    • 2014-10-31
    • 2015-05-08
    相关资源
    最近更新 更多