gpt4 book ai didi

macos - sed仅替换特定文件的第一个前导空格匹配-处理仅CR的行尾

转载 作者:行者123 更新时间:2023-11-29 09:46:52 24 4
gpt4 key购买 nike

编者按:
后来为了事后诸葛亮,对标题作了修改;有两个不同的问题:
(a)结果显示,输入文件只有\r-行结尾(仅限CR)(经典的Mac OS样式)
(b)尝试在\tregex中使用\rsed失败,因为BSD Sed(在OSX上使用)不支持这种转义。
我正在开发一个自动程序,它使用Python查找和替换文本文件中的某些单词。程序使用字典,有些实例中用作替换的值是''(意思是,没有)。我不认为这个程序引起了这个问题,但我只是在上下文中提到这个问题。(我认为问题在于sed,所以我不愿意标记Python。)
文件中的某些行有前导空白,这些空白是在文件开头的某些单词被空替换后无意中创建的。我想摆脱他们,我认为在这种情况下sed是最好的工具。
假设文本文件是这样的:

  Display
Display
BOX,

所以我使用以下命令通过 sed运行编辑过的文件:
sed -e 's/^[ \t]*//g'

结果是:
 Display
Display
BOX,

只编辑第一个匹配项。为什么?
通过测试,我创建了一个全新的纯文本文件,如下所示:
 hello
hello
hello

然后我对它运行上面的命令。这确实如预期的那样有效。为什么?
是否可能使用了其他形式的空间(不可打印字符?)是由Python程序创建的?但为什么 sed至少要工作一次呢?
顺便说一句,我正在开发另一个与OS X兼容的便携式解决方案或工具,用于修剪纯文本文件中每一行的前导空白。
编辑:这里是文件的一些 xxd输出(用X替换了大多数实际内容):
0000000: 2044 6973 706c 6179 2043 616c 6962 7261   X X
0000010: 7469 6f6e 2046 6978 7475 7265 2046 4952 X X X
0000020: 4d57 4152 4520 4b49 545e 4d20 4469 7370 X X^M X
0000030: 6c61 7920 4361 6c69 6272 6174 696f 6e20 X X
0000040: 4669 7874 7572 6520 524d 6163 426f 6f6b X X
0000050: 2041 6972 2028 3131 2d69 6e63 682c 204d X X
0000060: 6964 2032 3031 3229 2050 4f52 5420 4b49 X X) X X
0000070: 545e 4d42 4f58 2c20 5245 434f 5645 5259 T^MBOX, X

最佳答案

tl;博士
下面的任何解决方案都不会更新输入文件;独立的sed命令可以使用-i ''进行调整;需要先将awk解决方案保存到其他文件。
操作系统的输入似乎是一个只有换行符的经典Mac OS文件
谢谢,阿尔维斯。
.
\r总是读取这样一个文件作为一个整体,这通常是不需要的,并且妨碍了OP的行前导空白裁剪方法。
sed因此是更好的选择,因为它允许指定什么构成换行符(通过所谓的输入记录分隔符):
更新:将原来的awk命令替换为更简单、更快的替代命令,改编自peak's solution

awk -v RS='\r' '{ sub(/^[ \t]+/, ""); print }'

如果还可以从每一行中修剪尾随空格(如果有的话),并将每一行中单词之间的空格规格化为一个空格,则可以简化为:
awk -v RS='\r' '{ $1=$1; print }'

请注意,输出线将被 awk分开,这是通常需要的。
有关解释和背景信息,包括如何将 \n保留为换行符,请继续阅读。
注:答案的第一部分一般适用,但假设输入有以 \r结尾的行;OP的特殊情况(行显然仅以 \n结尾)在第二部分中处理。
在OSX上使用的BSD Sed只支持 \r作为控制字符转义序列;因此, \n用于匹配制表符。不支持。
要仍然匹配制表符,可以拼接 ANSI C-quoted string以生成实际的制表符。在Sed脚本中( \t):
sed 's/^[ '$'\t'']*//'

在这个简单的例子中,可以对整个Sed脚本( $'\t')使用ansic引用的字符串,但对于更复杂的脚本,这可能会变得棘手,因为这些字符串有自己的转义规则。
请注意,选项 sed -e $'s/^[ \t]*//'已被删除,因为它是无意义的,因为regex被锚定到输入的开头( g)。
关于GNU和BSD-Sed之间差异的总结,请参见我的 this answer
正如@alvits在注释中指出的,输入文件实际上可能有 ^实例,而不是Sed需要分隔行的 \r实例。
也就是说,该文件可能具有OSX Mac OS之前的行终止符:一个 \n \r终止一个行。
一种简单的验证方法是将输入文件传递给 by itself:将 cat -et实例可视化为 \r,而将 ^M实例可视化为 \n(另外, $实例可视化为 \t)。
如果输出中只有 ^I个实例,但没有 ^M个实例,则意味着行不会以 $结尾(同时),整个输入文件被视为单个字符串,这就解释了为什么只处理第一个输入“行”: \n只在整个字符串的最开始处匹配。
由于Sed解决方案(不进行预处理)会导致整个文件作为一个整体被读取,因此 ^是更好的选择:
要按照类Unix平台上的惯例创建分离的输出:
awk -v RS='\r' '{ sub(/^[ \t]+/, ""); print }'

awk告诉Awk通过 \n实例将输入拆分为记录(特殊变量 -v RS='\r'包含输入记录分隔符)。
\r搜索输入行上第一个出现的regex RS,并将其替换为 sub(/^[ \t]+/, ""),即,它有效地修剪了每个输入行的前导空格和制表符。注意,不带显式第三个参数的 ^[ \t]+隐式操作整个输入行。
""然后打印可能修改的输入行。
由于 sub()是Awk的默认输出记录分隔符( $0),输出记录将被 print终止。
如果您真的想保留 \n作为行分隔符:
awk 'BEGIN { RS=ORS="\r" } { sub(/^[ \t]+/, ""); print }'

OFS将输入和输出记录分隔符设置为 \n
如果还可以从每一行中删去尾随空格(如果有的话),并将每一行中单词之间的空格规格化为一个空格,则可以将以 \r结尾的变量简化为:
awk -v RS='\r' '{ $1=$1; print }'

不使用 RS=ORS="\r"(也不设置 \r,脚本中的输入字段分隔符)意味着Awk通过运行空格(空格、制表符、换行符)将输入记录拆分为字段。
\n是一种虚拟赋值,其目的是触发输入行的重新生成,每当字段变量被赋值时,都会发生这种情况。
该行通过将字段与输出字段分隔符(默认为单个空格)连接来重建。
实际上,前导空格和尾随空格因此被修剪,每行内部空白都被规范化为一个空格。
如果你想坚持 -F1
-即使这意味着一次读取整个文件:
sed $'s/^[ \t]*//; s/\r[ \t]*/\\\n/g' # note the $'...' to make \t, \r, \n work

这将输出以 FS结尾的行,这在Unix上是常见的。
相比之下,如果您希望保留 $1=$1作为行分隔符,请使用以下内容-但请注意,BSD Sed将始终在最后添加一个 OFS
 sed $'s/^[ \t]*//; s/\r[ \t]*/\r/g'  

[1] peak's answer最初更清楚地显示了一个实用的多用途替代方案:使用 sed将所有 \n实例替换为 \r实例,并将结果传递到原始 \n命令的BSD Sed友好版本:
\r

关于macos - sed仅替换特定文件的第一个前导空格匹配-处理仅CR的行尾,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35327981/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com