【问题标题】:How to avoid bash replacing `!^` as special character? [duplicate]如何避免 bash 将 `!^` 替换为特殊字符? [复制]
【发布时间】:2023-02-24 06:13:02
【问题描述】:

所以,我试图将几个.csv 文件合并到一个大文件中,但所有这些文件都有 csv-header。我已经创建了轻型 python 脚本,但它的运行速度太慢了。所以,我决定只使用 linux utils 来这样做(只是为了好玩和更好地了解它)。


  1. 首先,我将所有文件与cat 合并为一个文件(我不知道为什么,但less 添加了一些奇怪的输出,例如我传递给他的文件的文件名):
    cat location/to/files/*.csv >> large_combined.csv
    
    1. 然后,我注意到,每个csv 文件的标头都与每个文件的最后一条记录相连接,例如
    zero,first,second,third
    0,1,2,3
    0,1,2,3
    0,1,2,3zero,first,second,third
    0,1,2,3
    
    1. 我不想只替换所有标题,然后在修改后的文件的第一行添加一个,因为它太简单了,我想用一个 sed 命令替换所有标题(只是为了更好地了解这个实用程序,因为如果它不是那么简单怎么办?添加标题不会帮助我完成其他类似的任务),所以我带来了这个regex,它会找到每个没有放在行首的标题(所以,基本上 - 每个标题,除了第一个)
    (?<!^)(zero,first,second,third\b)
    
    1. 然后简单地运行它:
    sed -E "s/(?<!^)(zero,first,second,third\b)//g" large_combined.csv
    
    1. 但是 bash 以某种方式决定在执行之前将 !^ 转换为 -E,这样我的 sed 看起来像这样:
    sed -E "s/(?<-E)(zero,first,second,third\b)//g" large_combined.csv
    sed: -e expression #1, char 280: Invalid preceding regular expression
    

    所以,我的问题是 -如何防止 bash 将 !^ 转换为 -E


    附言!^ 返回在当前或上一步给出的参数,因此它可以使任何其他程序崩溃,如下所示:

    ls -la ./!^
    ls: cannot access './-la': No such file or directory
    

    而且这种行为非常烦人,尤其是对于任何使用regex的程序

【问题讨论】:

  • sed 没有环顾四周。 (?&lt;按字面解释。 First, I've combined all files in one with cat首先,对于每一个文件,不带第一行输出,然后cat
  • 得到类似 0,1,2,3zero,first,second,thirdcat 的东西意味着你的 CSV 文件末尾没有强制换行符
  • 这不是我的 csv,也不是主要问题:)
  • 您的 CSV 文件没有以换行符正确终止,正如处理文本文件的 POSIX 实用程序所期望的那样。 (根据定义,POSIX 文本文件是行的集合,其中一行定义为由换行符终止的字符串。文件的最后一行也不例外。)
  • 如果您先修复 CSV 文件,剩下的就简单多了。

标签: linux bash sed


【解决方案1】:

使用单引号 (') 而不是双引号 (")。 Bash 会解释双引号中的内容,但会按原样使用单引号中的所有内容。

【讨论】:

  • PS:不要为了学习东西而使用使事情变得更难的东西。将有足够的机会使用更合适的所述内容。
  • PPS:使用sed '/yourregexhere/d'删除匹配行,而不是's/yourregexhere//g'
  • 哇,没想到会有这种行为。谢谢你! (PS。我已经说过,我正在尝试过于复杂化以更加理解它。看,如果我没有决定“艰难” - 我从来没有遇到过这个问题。)
  • 现在,是时候了解为什么sed 仍然不认识这个regex
【解决方案2】:

我不得不说,似乎最适合这项任务的标准工具是awk

awk 'FNR != 1 || NR == 1' location/to/files/*.csv > large_combined.csv
说明
  • 条件FNR != 1 选择除每个文件的第一行以外的所有行
  • 条件NR == 1选择第一个文件的第一行
  • 然后,使用FNR != 1 || NR == 1,awk 将完整地输出第一个文件和所有行,但其余文件的第一行除外

【讨论】:

  • 看起来又酷又快呢!谢谢你!也许在以后的使用中会切换到awk
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-04-16
  • 2017-07-05
  • 2017-10-19
  • 1970-01-01
  • 2015-03-17
  • 2019-11-04
  • 2012-11-16
相关资源
最近更新 更多