【问题标题】:Splitting a line in bash based on delimiter with Sed / Regex使用 Sed / Regex 基于分隔符在 bash 中拆分一行
【发布时间】:2013-09-19 07:32:36
【问题描述】:

正则表达式新手,希望能改变这一点。我有以下看似非常简单的问题,我无法正确解析正确的正则表达式实现。基本上我有一个文件,它的行看起来像这样:

time:3:35PM

我只是想删除所有字符,包括仅第一个':'分隔符,并使用 sed 保持其余字符不变,以便我可以处理许多具有相同格式的文件。我想要得到的是:

3:35PM

下面是我得到的最接近的,但只是使用最后一次出现的分隔符而不是第一次出现。:

sed 's/.*://'

我也尝试过使用 python,但在应用 python 函数来遍历许多文件中的所有行而不是一个文件时遇到了挑战。

任何帮助将不胜感激。

【问题讨论】:

  • 贪婪匹配,嗯? :) 试试这个:sed 's/[^:]*://'

标签: regex bash sed


【解决方案1】:

要删除直到: 的每个实例,包括:,您可以这样做..

sed -i.bak 's/^[^:]*://' file.txt

在多个.txt 文件上

sed -i.bak 's/^[^:]*://' *.txt

-i 选项指定要就地编辑文件。通过创建一个临时文件并将输出发送到该文件而不是标准输出。

【讨论】:

    【解决方案2】:

    由于您不需要正则表达式来匹配单个已知字符,请考虑使用 而不是。

    这个简单的表达式将: 设置为d-elimiter 并发出f-ields 2,向前(-):

    cut -d: -f2-
    

    例子:

    % echo 'time:3:35PM' | cut -d: -f2-
    3:35PM
    

    【讨论】:

    • 谢谢。我试过了,但据我了解,您不能使用 cut 对多个文件进行就地编辑。
    • @prometheus2305:确实如此,cut 不进行就地编辑,但也不是所有 sed 实现。
    • 谢谢。我绝对专注于就地编辑。因此,如果我理解正确,我需要使用“ed”
    • @prometheus2305: ed 肯定会完成这项工作(如kojiro's answer 所示)。使用您最熟悉的工具。
    【解决方案3】:

    您几乎可以在所有文本处理工具中执行此操作(许多根本不使用正则表达式)。

    编辑

    如果就地编辑真的很重要,那么规范的正确方法不是 sed(stream 编辑器)而是ed(file 编辑器)。

    ed "$file" << EOF
    ,s/^[^:]*://g
    w
    EOF
    

    sed

    (与 ed 几乎相同的命令,格式略有不同)

    sed 's/^[^:]*://' < "$file" > "$file".new
    mv "$file".new "$file"
    

    重击

    这不会导致产生任何新进程。 (不管它值多少钱。)

    while IFS=: read _ time; do
        printf '%s\n' "$time"
    done < "$file" > "$file".new
    mv "$file".new "$file"
    

    awk

    awk -F: 'BEGIN{ OFS=":" } { print $2,$3 }' < "$file" > "$file".new
    mv "$file".new "$file"
    

    剪切

    cut -d: -f2- < "$file" > "$file".new
    mv "$file".new "$file"
    

    【讨论】:

    • 不错!甚至不知道'ed'。谢谢你。请问您如何将 ed 选项递归地应用于包含多个文件的多个目录?
    • @prometheus2305 如果你的 shell 可以递归地 glob,你可以循环遍历那个 glob 表达式,比如for f in **/*; do ed "$f" &lt;&lt;&lt; "$edscript"; done。否则,您需要将find 与脚本一起使用。类似find . -type f -name "$filepattern" -exec sh -c 'ed "$1" &lt;&lt;&lt; "$edscript"' _ {} \;
    • 这很全面。我会先做mv "${file}" "${file}.bak"" 然后使用&lt; "${file}.bak" &gt; "${file}" 进行编辑,留下备份文件以防万一。
    【解决方案4】:

    kojiro's answer 有很多不错的选择,但您已经问过如何使用regex 来做到这一点。以下是一些纯正则表达式解决方案:

    grep -oP '[^:]*:\K.*' file.txt
    

    \K 使它忘记\K 出现之前的一切。 但是,如果您知道确切的前缀长度,那么您可以使用lookaround 功能:

    grep -oP '(?<=^time:).*' file.txt
    

    请注意,大多数正则表达式实现不支持这些功能。您可以在 grep 中使用它,带有 -P 标志和 perl 本身。我想知道是否有任何其他实用程序支持这些。

    【讨论】:

      【解决方案5】:

      请考虑我的回答:

      How to use regex with cut at the command line?

      例如,您可以只写:

      echo 'time:3:35PM' | cutr -d : -f 2- -r :
      

      在您的特定情况下,您可以简单地使用cut:

      echo 'time:3:35PM' | cut -d : -f 2-
      

      欢迎任何反馈。 cutr 还不完美,但在我投入太多时间之前,我想获得一些反馈。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-05-08
        • 1970-01-01
        • 1970-01-01
        • 2018-03-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多