Answers:
如果您有GNU,则可以使用这个不错的oneliner sed
。
sed -i '$ d' ./*
它将删除当前目录中每个未隐藏文件的最后一行。-i
GNU的Switch sed
表示就地操作,并'$ d'
命令sed
删除最后一行($
意味着last和d
delete)。
-i
是GNUism,所以这没有什么意义,但是如果我未能指出某些旧版本的sed
不允许您在$
和之间放置任何空格,那么我将失去旧的胡须d
。通常,在模式和命令之间)。
*(.)
glob来存储常规文件,而我不了解其他shell。
如果目录包含常规文件或文件名中带有空格/换行符的文件,则其他所有答案均存在问题。无论如何,这都是可行的:
find "$dir" -type f -exec sed -i '$d' '{}' '+'
find "$dir" -type f
:在目录中找到文件 $dir
-type f
是常规文件;-exec
在找到的每个文件上执行命令sed -i
:在适当位置编辑文件;'$d'
:删除(d
)最后($
)行。'+'
:告诉find继续添加参数sed
(由于@zwol,比分别为每个文件运行命令效率更高)。如果您不想进入子目录,则可以将参数添加-maxdepth 1
到中find
。
find
可以更高效地编写find $dir -type f -exec sed -i '$d' '{}' '+'
。)
-print0
在完整命令中不存在,为什么要添加到解释中?
-depth 0
它不起作用(findutils 4.4.2),应该改为-maxdepth 1
。
-exec
。
使用GNU sed -i '$d'
意味着读取完整文件并在没有最后一行的情况下对其进行复制,而仅将文件截断到位(至少对于大文件而言)会更有效率。
使用GNU truncate
,您可以执行以下操作:
for file in ./*; do
[ -f "$file" ] &&
length=$(tail -n 1 "$file" | wc -c) &&
[ "$length" -gt 0 ] &&
truncate -s "-$length" "$file"
done
如果文件相对较小,则效率可能会降低,因为每个文件运行多个命令。
请注意,对于在最后一个换行符之后(在最后一行之后)包含额外字节的文件,或者换句话说,如果文件的最后一行没有分隔符,那么根据tail
实现的不同,文件tail -n 1
将仅返回那些额外的字节(例如GNU tail
),或最后一行(正确定界)以及那些额外的字节。
|wc -c
在tail
电话吗?(或a ${#length}
)
${#length}
因为它计算字符数而不是字节数,所以将不起作用,并且$(...)
将删除尾部的换行符,因此${#...}
即使所有字符都是单字节的,也将被一掉。
一种更可移植的方法:
for f in ./*
do
test -f "$f" && ed -s "$f" <<\IN
d
w
q
IN
done
我不认为这需要任何解释......除了可能在这种情况下d
是一样的$d
,因为ed
默认情况下选择的最后一行。
这不会递归搜索,也不会处理隐藏文件(又名dotfiles)。
如果您也想编辑它们,请参阅如何将*与目录中的隐藏文件进行匹配
[[]]
为,[]
则它将完全符合POSIX。([[ ... ]]
是Bashism。)
[[
不是bashism)
递归地从当前目录开始的所有文件(包括点文件)的POSIX兼容单行代码:
find . -type f -exec sh -c 'for f; do printf "\$d\nx\n" | ex "$f"; done' sh {} +
.txt
仅对于文件(非递归):
find . -path '*/*/*' -prune -o -type f -name '*.txt' -exec sh -c 'for f; do printf "\$d\nx\n" | ex "$f"; done' sh {} +
另请参阅: