Awk 使用';sed';删除特定字符的换行符的步骤

Awk 使用';sed';删除特定字符的换行符的步骤,awk,sed,Awk,Sed,我知道这个问题有过不同的提问和回答。但我的重点是为什么sed的行为不像我期望的那样 对于一个给定的threaddump文件,我需要在每一行“锁定可拥有的同步器”之前删除换行符,如下所示 at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175) at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awa

我知道这个问题有过不同的提问和回答。但我的重点是为什么sed的行为不像我期望的那样

对于一个给定的threaddump文件,我需要在每一行“锁定可拥有的同步器”之前删除换行符,如下所示

        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
    at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
    at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
    at com.project.tools.threads.NamedThread.run(NamedThread.java:37)

   Locked ownable synchronizers:
        - None
我可以使用vi实现这一点:

:g/^M   Locked ownable synchronizers/s//   Locked ownable synchronizers/g
^^^^M是ctrl-M。上面的vi命令有效,即,它在锁定前成功删除换行符。然而,当我尝试在sed中使用它时,以下工作都没有完成(我尝试了多种方法来表示换行符,但都没有成功)

据我所知,vi命令在sed中工作(它们一直在工作)。为什么这个不管用

多谢各位

PS:有效的解决方案是使用perl:

perl -0pe 's/\n   Locked ownable synchronizers:/   Locked ownable synchronizers:/g' < file.threaddump
perl-0pe的/\n锁定的可拥有同步器:/Locked ownable synchronizers:/g'

但我想弄明白为什么sed不起作用

首先,在vim中工作的一个更简单的
ex
命令是:

:%s/\n\(   Locked\)/\1/
现在,用sed替换换行并不简单,因为sed逐行读取其输入,对于sed,一行本身不包含换行符(换行符只是行之间的分隔符)。因此,默认情况下,包含
\n
的sed模式将不匹配任何内容

以前曾提出过用sed替换换行的问题,我们可以根据您的情况采用:

sed -e :a -e N -e '$!ba' -e 's/\n\(   Locked\)/\1/' file.threaddump

对于这样一个简单的任务,上面的解决方案相当复杂,因为它试图让sed做一些它不打算做的事情,即匹配换行符

这个故事的寓意是:为工作选择正确的工具。

在这种情况下,更好的工具是允许重新定义记录分隔符的工具,以便换行符在字符串中显示为普通字符,而不被视为记录分隔符

Sed不允许这样做,因为它是专门为处理行而设计的,并且换行符被硬编码为记录分隔符

但是,正如您已经看到的,Perl允许使用
-0
开关执行此操作:

perl -0 -p -e 's/\n(   Locked)/$1/' file.threaddump
-0
开关(不带参数)基本上将记录分隔符设置为空字符串,从而将整个输入视为单个记录。然后可以像
s//
命令中的任何其他字符一样匹配换行符
\n


注意:


如果您想删除回车符
\r
(U+000D)而不是换行符
\n
(U+000A),您应该能够将上述代码中的
\n
替换为
\r

首先,在vim中工作的一个更简单的
ex
命令是:

:%s/\n\(   Locked\)/\1/
现在,用sed替换换行并不简单,因为sed逐行读取其输入,对于sed,一行本身不包含换行符(换行符只是行之间的分隔符)。因此,默认情况下,包含
\n
的sed模式将不匹配任何内容

以前曾提出过用sed替换换行的问题,我们可以根据您的情况采用:

sed -e :a -e N -e '$!ba' -e 's/\n\(   Locked\)/\1/' file.threaddump

对于这样一个简单的任务,上面的解决方案相当复杂,因为它试图让sed做一些它不打算做的事情,即匹配换行符

这个故事的寓意是:为工作选择正确的工具。

在这种情况下,更好的工具是允许重新定义记录分隔符的工具,以便换行符在字符串中显示为普通字符,而不被视为记录分隔符

Sed不允许这样做,因为它是专门为处理行而设计的,并且换行符被硬编码为记录分隔符

但是,正如您已经看到的,Perl允许使用
-0
开关执行此操作:

perl -0 -p -e 's/\n(   Locked)/$1/' file.threaddump
-0
开关(不带参数)基本上将记录分隔符设置为空字符串,从而将整个输入视为单个记录。然后可以像
s//
命令中的任何其他字符一样匹配换行符
\n


注意:


如果您想删除回车符
\r
(U+000D)而不是换行符
\n
(U+000A),您应该能够将上述代码中的
\n
替换为
\r

sed一次读取并操作一行。行由换行符分隔。因此,您不能从sed操作的行中删除换行符,因为它不包含换行符

由于sed仅用于单个行上的简单替换,因此您无论如何都应该使用awk:

awk -i inplace -v RS='^$' '{print gensub(/\n(\s*Locked ownable synchronizers)/,"\\1","g")}' file.threaddump

上面使用GNU awk而不是GNU sed进行就地编辑和其他语法分析。

sed一次读取和操作一行。行由换行符分隔。因此,您不能从sed操作的行中删除换行符,因为它不包含换行符

由于sed仅用于单个行上的简单替换,因此您无论如何都应该使用awk:

awk -i inplace -v RS='^$' '{print gensub(/\n(\s*Locked ownable synchronizers)/,"\\1","g")}' file.threaddump
上面使用GNU awk而不是GNU sed进行就地编辑和其他语法调整。

这可能适合您(GNU sed):

将第二行附加到第一行,如果该行以所需字符串开头,请删除前面的换行符并重复。否则,打印第一行,删除它并重复。

这可能适合您(GNU-sed):


将第二行附加到第一行,如果该行以所需字符串开头,请删除前面的换行符并重复。否则打印第一行,删除并重复。

您的解释很有道理,我对sed有了更好的理解。谢谢!你的解释有道理,我有更好的解释