删除每行倒数第二个字符 - 使用 sed

删除每行倒数第二个字符 - 使用 sed

如何删除文件中每行最后一个字符之前的字符?

我尝试sed 's/.$//' myfile1.txt删除每行的最后一个字符myfile1.txt,但我不确定如何删除每行的倒数第二个字符。

答案1

你可以做:

sed -E 's/.(.)$/\1/' file.txt  

要就地编辑文件而不进行备份:

sed -Ei 's/.(.)$/\1/' file.txt 

要就地编辑文件,并使用.bak扩展名备份原始文件:

sed -Ei.bak 's/.(.)$/\1/' file.txt 

POSIX 风格:

sed 's/.\(.\)$/\1/' file.txt

答案2

完整解释可移植命令(既然有人问了)这样任何人都可以理解这一点:

sed 's/.\(.\)$/\1/' file.txt

首先,“显而易见”:这一行包含一个命令名称 ( sed) 和两个由 shell 传递给该命令的单独参数。单引号被 shell 去掉,所以sed“看到”的参数是:

s/.\(.\)$/\1/

file.txt

由于没有任何参数以sed连字符开头,因此它不会将它们解释为选项。

第一个参数被解释为要运行的编辑命令,任何其他参数(在本例中只是一个,file.txt)被解释为从中读取要由编辑命令编辑的文本的文件的名称(第一个参数) 。

(请注意,编辑后的文本将写入sed“标准输出”,即返回到终端、命令行窗口,而不是写回文件。)

file.txt必须是执行此命令时位于 shell 的“当前工作目录”目录中的文件的文件名sed。 (如果您希望命令在同一文件上运行,无论运行该命令时 shell 的当前工作目录是什么,请阅读“绝对路径”。)


现在我们将解构编辑命令本身:

s/.\(.\)$/\1/

编辑命令以字母 开头s,代表“替换”。从“s”后面的字符(/在本例中)到该同一字符的下一个实例(/再次),是图案是要被替换的。换句话说,它指定要被替换的文本应该“看起来像什么”——它告诉sed如何“知道”何时找到了应该被替换(应该被替换)的文本。

本例中的模式是:

.\(.\)$

(代替“模式”的正确术语实际上是正则表达式,最初是“正则表达式”的缩写。我不会在这里讨论更广泛的正则表达式主题。)

该正则表达式以点 ( .) 开头,它是一个“通配符”,含义为“任何单个字符”。它火柴(描述、象征)文本的任何单个字符。

反斜杠 ( \) 经常在 shell 命令和正则表达式中用作“转义”字符。一般来说,这意味着要么删除它后面的字符的特殊意义,或者它添加对于以下字符具有特殊意义。

在这种情况下,括号(和()逃脱了(也就是说,前面有一个反斜杠)为了添加有特殊的意义。正则表达式中转义括号的特殊含义sed是,任何与括号之间的正则表达式部分匹配的文本都会被特别“注释”,并且可以转回到。我们稍后会再讨论这一点(当我们回顾这个括号分组时)。

.括号内的句点 ( ) 再次匹配任何单个字符。

美元符号 ( $) 称为锚,它匹配一行文本的末尾。 如果没有这个锚点,正则表达式将简单地匹配任意两个字符(具体来说,它将匹配从名为 的文件中读取的每行文本的前两个字符file.txt),并且(由于转义括号)sed将“注释”这两个字符中的第二个字符,以便稍后引用。

因为正则表达式是锚定的到行尾,两个点必须匹配最后的每行文本上有两个字符(最后一个字符会被注明以供稍后参考)。

(替换)命令的下一部分s是从后面的字符的第二个实例s(在本例中是斜杠,/)到后面的字符的第三个实例s。这被称为替换模式。 它指定了sed应该做什么代替匹配的文本搜索模式(正则表达式)。

在这种情况下,替换模式是:

\1

同样,反斜杠用于逃脱接下来的字符,在这种情况下又是添加具有特殊意义,而不是消除特殊意义。

反斜杠后跟数字(从 1 到 9)称为反向引用。 这是什么回指搜索模式中括号内匹配的文本分组。由于数字是1,这指的是第一的括号分组。 (当然,在这种情况下,只有一个这样的分组。)

总而言之,这个编辑命令的意思是使用那些转义括号(即该行的最后一个字符)内匹配的文本来替换由转义括号匹配的文本。全部的搜索正则表达式(这是最终的该行的字符)。

最终效果是从每行中删除倒数第二个字符。

或者,更准确地说,将从当前工作目录中sed名为 find 的文件中读取每一行文本;file.txt对于每一行,它将替换最后一行该行的字符以及该行的单个最终字符;它会将每个修改的行打印到其标准输出。

相关内容