通过截断删除Bash中文件中的尾随空白行

时间:2014-11-01 18:29:19

标签: linux bash

有没有办法使用Bash删除文件末尾的任何尾随空白行(只包含空格的行)?

例如,这个:

123\n\n\n12\n  \n \t \n

应该成为:

123\n\n\n12\n

我知道如何在C中使用fseek()和ftruncate(),但不确定是否可以使用bash和现成的cmd-line实用程序,而无需创建专门的C程序为了它。

我已经看到一些问题,一般要求删除尾随空格,例如How to remove trailing whitespace of all files recursively?,但是我要求通过截断而不是覆盖文件来执行此操作(出于性能原因)。

2 个答案:

答案 0 :(得分:3)

您可以使用tac找到尾随空白行,然后使用dd截断:

#!/bin/bash
file=$1
trailing=$(tac "$file" | sed -n '/^[ \t]*$/!q; p' | wc -c)
end=$(( $(wc -c < "$file") - trailing ))
dd bs=1 seek=$end count=0 of="$file"

答案 1 :(得分:0)

我非常喜欢@that other guy的答案。

但是,这是另一种可能性,它使用命令替换删除尾随换行的事实,并且不会读取文件两次以计算应该修剪它的位置。

#!/bin/bash

file=$1
tokeep=$(wc -c <<< "$(< "$file")") || exit $?
dd if=/dev/null of="$file" bs=1 seek=$tokeep

如果要删除尾随空格(即换行符,空格,制表符等),请使用tr将空格替换为换行符,以便丢弃尾随空格:

#!/bin/bash

file=$1
tokeep=$(wc -c <<< "$(tr '[[:space:]]' '\n' < "$file")") || exit $?
dd if=/dev/null of="$file" bs=1 seek=$tokeep

这会保留一个尾随换行符(因为here-string <<<会添加换行符)。如果你想修剪这个尾随换行符(但实际上你不应该!),请在seek=$tokeep语句中用seek=$((tokeep-1))替换dd

注意。 [[:space:]]字符类依赖于语言环境。在C和POSIX语言环境中,它对应于空格,换页\f,换行符\n,回车\r,水平标签\t和垂直标签\v (见man 3 isspace 1 。您也可以制作自己的一组字符:如果您只想修剪尾随的换行符和制表符,但保留所有其他空格,请使用

tr '\t' '\n'

1 这很好,因为它们都是一个字节长,但是如果您的语言环境有超过一个字节的空格(例如,一个牢不可破的空格{{1}),请不要使用它是UTF-8编码为两个字节U+00A0)。如果不确定正在使用的语言环境,则应在C2 A0中使用自己的字符,例如tr,以确保它们都是一个字节长。如果您还想处理两个字节字符,则应使用两个换行符替换它们,例如使用'\t '。具有牢不可破的空间的示例:

sed

假设您有UTF-8语言环境。这有点笨拙,可能超出了原始问题的范围。