Answers:
如果您有GNU,则可以使用这个不错的oneliner sed。
sed -i '$ d' ./*
它将删除当前目录中每个未隐藏文件的最后一行。-iGNU的Switch sed表示就地操作,并'$ d'命令sed删除最后一行($意味着last和ddelete)。
-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 {} +
另请参阅: