我有大量的源文件,最后都没有换行符。如何解决大量文件的“文件末尾没有换行符”警告?
如何自动添加换行符到每个换行符的结尾?
有些可能已经有换行符,所以只能在必要时添加。
我可能不是在寻找代码本身,而只是在终端中运行以添加必要的换行符(或某种编程或开发工具)。
我有大量的源文件,最后都没有换行符。如何解决大量文件的“文件末尾没有换行符”警告?
如何自动添加换行符到每个换行符的结尾?
有些可能已经有换行符,所以只能在必要时添加。
我可能不是在寻找代码本身,而只是在终端中运行以添加必要的换行符(或某种编程或开发工具)。
为了方便起见,将诺曼的答案转换为分离式单行程。
for i in * ; do echo $i; \
if diff /dev/null "$i" | tail -1 | \
grep '^\\ No newline' > /dev/null; then echo >> "$i"; \
fi; done
替换*与任何你想要的文件模式,例如*.c
,另一个只是告诉你哪些文件被破坏:
for i in * ; do \
if diff /dev/null "$i" | tail -1 | \
grep '^\\ No newline' > /dev/null; then echo $i; \
fi; done
如果你有机会获得Unix工具,你可以运行diff
找出哪些文件缺乏一个换行符,然后将其追加:
#!/bin/sh
for i
do
if diff /dev/null "$i" | tail -1 | grep '^\\ No newline' > /dev/null
then
echo >> "$i"
fi
done
我靠diff
生产具有在\
消息第一列tail
给我最后一行diff
的输出,并且grep
告诉我最后一行是否是我正在查找的消息。如果一切正常,则echo
会生成一个换行符,>>
会将其附加到文件"$i"
。如果文件名中有空格,"$i"
左右的引号可以确保事情仍然有效。
不错,但是grep会返回一个本地化的消息,比如“\ Brak znaku nowej linii(etc.)”。另外,diff输出整个文件。我会使用'tail -1 $ f | grep'\ n''的条件(在我的盒子上工作)。 – 2012-12-12 12:46:59
@TomaszGandor:'tail -1 filename | grep'\ n'似乎总是在我的mac上返回一个错误的结果,不管是否有尾随的换行符。 – Gino 2017-05-27 14:03:39
OK,在评论抱怨后,有我更好的解决方案 首先,你要知道,这些文件丢失换行符:
find -type f -exec sh -c "tail -1 {} | xxd -p | tail -1 | grep -v 0a$" ';' -print
不超快速(要求每个文件一对夫妇的进程),但它的实际用途确定。
现在,当你拥有了它,你不妨加入新行,与其他-exec
:
find -type f -exec sh -c "tail -1 {} | xxd -p | tail -1 | grep -v 0a$" ';' -exec sh -c "echo >> {}" ';'
可能的陷阱:
如果文件名是不好的,例如他们有空间,您可能需要tail -1 \"{}\"
。 或确实找对了吗?
您可能想要添加更多的过滤来查找,如-name \*py
等。
想想可能的DOS/Unix换行在使用之前乱七八糟(首先修复)。
编辑:
如果你不喜欢这些命令的输出(呼应一些十六进制),加-q
到grep:
find -type f -exec sh -c "tail -1 {} | xxd -p | tail -1 | grep -q -v 0a$" ';' -print
find -type f -exec sh -c "tail -1 {} | xxd -p | tail -1 | grep -q -v 0a$" ';' -exec sh -c "echo >> {}" ';'
这是*巨大的*矫枉过正。 – tripleee 2015-08-29 09:29:11
由于指挥本地化Tim和诺曼答案应该使用'LANG = C'前缀进行改进,以便有机会与每个具有任何区域参数的系统匹配'无换行'模式
这确保了结束空行把这个脚本的命令行上的每个文件:
#!/bin/sh -f
for i in $* ; do echo $i; \
if LANG=C diff /dev/null "$i" | tail -1 | \
grep '^\\ No newline' > /dev/null; then echo >> "$i"; \
fi; done
而这个脚本检测缺乏的是文件:
#!/bin/sh -f
for i in $* ; do \
if LANG=C diff /dev/null "$i" | tail -1 | \
grep '^\\ No newline' > /dev/null; then echo $i; \
fi; done
尝试前路:
ex -s +"bufdo wq" *.c
,并递归(启用a new globbing option):
ex -s +"bufdo wq" **/*.c
这相当于vi -es
。更改*.c
以扩展您的兴趣。
如果不存在,ex
/vi
会在保存时自动附加新行。
找到工具后,做这个工作没有运气。我决定写我自己的
这是我的Python脚本来完成这项工作
只追加(\ r \ n)与文件不包含(\ n)的在文件的结尾
https://github.com/tranhuanltv/append_newline
用法:append_newline.py .C ./projects ./result_dir
制作引入请求,如果你想
这是非常值得怀疑的 - 从END开始寻找-1是可以的,但是你可以用这种方法轻松地混合使用Unix和DOS换行符...... – 2016-04-01 07:26:57
我很惊讶没有人已经提到像Awk这样的许多简单的文本处理工具会添加一个换行符作为副作用。这是一个简单的循环,只有在实际添加换行符时才会覆盖文件。
for f in *; do
awk 1 "$f" >tmp
cmp -s tmp "$f" || mv tmp "$f"
done
rm -f tmp
(临时文件显然是有点疣。)
IDEone演示:http://ideone.com/HpRHcx
pcregrep --recursive --exclude-dir=.git \
--files-without-match --multiline '\n\z' . |
while read k ; do echo >> "$k"; done
这里涉及到几个步骤:
步骤1历来与find
做(以下 Unix的传统“每个工具做一两件事,做的很好”),但由于pcregrep具有内置的支持,我很舒服使用它。我小心避免乱七八糟的.git文件夹。
步骤2用多正则表达式匹配做有一个最后的换行的文件,并打印该不匹配文件名来完成。
步骤3是用while/read循环而不是for/in完成的,因为后者失败了包含空格的文件名和极长的文件列表。
步骤4是一个简单的回声,遵循@ norman-ramsey的方法。
h/t @ anthony-bush https://stackoverflow.com/a/20687956/577438为pcregrep建议。
我使用find
代替for f in *
,因为它是递归的,问题是关于“大量的源文件”。
由于性能方面的原因,我使用的是while read
而不是find -exec
或xargs
,它每次都会节省产卵shell进程。
我正在利用反引号操作符正在返回命令的输出,“任何尾随的换行符被删除”man bash
,因此对于正确终止的文件,反引号将为空,并且回显将被跳过。
的find | read
夫妇将无法对包含换行符的文件名,但它很容易,如果需要解决:
find -type f -print0 | while read -d $'\0' f; do [[ `tail -c1 "$f"` ]] && echo >> "$f"; done
下面是我的bash脚本的解决方案。它首先检查文件是否是文本文件。然后,如果它是一个文本文件,它使用tail和od(八进制转储)来查看最后一个字符是否是换行符。如果不是,那么就使用回声附加一个换行符:
item="$1"
if file "$item" | egrep '\btext\b' > /dev/null
then
if ! tail -c 1 "$item" | od -b -A n | egrep '\b012\b' > /dev/null
then
echo "(appending final newline to ${item})"
echo >> "$item"
fi
fi
一个简单的修正对于那些“失踪”换行符在文件末尾简单的sed文件;以下修复“就地”(使用“-i”选项)的文件:
find . -type f -exec sed -i -e '$a\' {} \; -print
说明:找到的所有文件(-type f
),运行sed
,更改文件就地(-i
),给定以下(-e
)脚本/表达式匹配文件末尾($
),并执行“追加”动作(a\
),但实际上并未指定要追加的任何文本(在\
之后没有任何内容)在文件的末尾添加一个换行符,但只有当文件末尾不存在时。打印找到的所有文件(固定或不固定),这可能是不必要的。
主要需要注意的是sed
功能因平台而异,所以-i
和-e
可能会或可能不会被支持/相同;例如较旧的Unix或MacOS的怪异可能需要稍微不同的语法。
这些解决方案都不适用于我 – 2012-11-10 10:09:58
如果您希望它以递归方式进行交换,可以交换'*'用'$(find。-type f)'或'$(找到 -type f -name )' –
durron597
2013-08-30 14:53:40