如何解决许多文件的“文件末尾没有换行”警告?

时间:2010-07-16 04:25:53

标签: shell scripting newline multiple-files

我有大量的源文件,最后都缺少换行符。

如何自动在每一行的末尾添加换行符?

有些可能已有换行符,因此只应在必要时添加。

我可能不会寻找代码本身,但只是我可以在终端中运行以添加必要的换行符(或某种编程或开发工具)。

10 个答案:

答案 0 :(得分:7)

如果您可以访问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"周围的引号可确保文件名中包含空格时仍可正常工作。

答案 1 :(得分:5)

为方便起见,将Norman的答案转换为拆分单行。

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

答案 2 :(得分:4)

对缺少"缺少的文件的简单修复"文件末尾的换行符就是sed;以下修复了文件"就地" (使用" -i"选项):

find . -type f -exec sed -i -e '$a\' {} \; -print 

说明:找到所有文件(-type f),运行sed,就地更改文件(-i),给定以下(-e)脚本/表达式,匹配文件的末尾($),并执行"追加"操作(a\),但实际上并未指定要追加的任何文本(\之后没有任何内容),这将在文件末尾添加换行符,但仅限于&# 39;失踪。打印找到的所有文件(固定与否),这可能是不必要的。

主要警告是sed功能因平台而异,因此-i-e可能支持也可能不支持/相同;例如较旧的Unix或MacOS奇怪可能需要稍微不同的语法。

答案 3 :(得分:3)

好的,在评论中抱怨之后,有更好的解决方案。 首先,您想知道哪些文件缺少换行符:

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 >> {}" ';'

答案 4 :(得分:1)

尝试前方:

ex -s +"bufdo wq" *.c

递归(启用a new globbing option):

ex -s +"bufdo wq" **/*.c

这相当于vi -es。将*.c更改为您感兴趣的扩展名。

ex / vi如果不存在,会自动在保存时添加换行符。

答案 5 :(得分:1)

以下是我的bash脚本解决方案。它首先检查该文件是否为文本文件。然后,如果它是一个文本文件,它使用tail和od(八进制转储)来查看最后一个字符是否是换行符。如果不是,则使用echo附加换行符:

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

答案 6 :(得分:0)

由于命令本地化,Tim和Norman回答应使用'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

答案 7 :(得分:0)

找到工具后做这项工作没有运气。我决定写自己的

这是我做这项工作的python脚本

它只附加(\ r \ n)文件末尾的文件不包含(\ n)

https://github.com/tranhuanltv/append_newline

用法:append_newline.py .c ./projects ./result_dir

如果您想

,请提出拉取请求

答案 8 :(得分:0)

我很惊讶没有人提到像Awk这样的许多简单的文本处理工具会添加换行符作为副作用。这是一个简单的循环,只有在实际添加换行符时才会覆盖文件。

13

(临时文件显然有点像疣。)

IDEone演示:http://ideone.com/HpRHcx

答案 9 :(得分:0)

pcregrep --recursive --exclude-dir=.git \
  --files-without-match --multiline '\n\z' . |
  while read k ; do echo >> "$k"; done

这里涉及以下几个步骤:

  1. 递归查找文件
  2. 检测哪些文件缺少尾随新行
  3. 遍历每个文件
  4. 附加换行符
  5. 传统上,步骤1使用find(遵循Unix的传统) "每个工具做一件事并且做得很好"),但由于pcregrep有内置的支持,我很舒服地使用它。我小心翼翼地避免弄乱.git文件夹。

    第2步是使用多行正则表达式匹配具有最终换行符的文件,并打印匹配的文件的名称。< / p>

    第3步是使用while / read循环而不是for / in完成的,因为后者对于带有空格的文件名和极长的文件列表都失败了。

    第4步是一个简单的回声,遵循@ norman-ramsey的方法。

    h / t @ anthony-bush https://stackoverflow.com/a/20687956/577438了解pcregrep建议。