我有大量的源文件,最後都沒有換行符。如何解決大量文件的「文件末尾沒有換行符」警告?
如何自動添加換行符到每個換行符的結尾?
有些可能已經有換行符,所以只能在必要時添加。
我可能不是在尋找代碼本身,而只是在終端中運行以添加必要的換行符(或某種編程或開發工具)。
我有大量的源文件,最後都沒有換行符。如何解決大量文件的「文件末尾沒有換行符」警告?
如何自動添加換行符到每個換行符的結尾?
有些可能已經有換行符,所以只能在必要時添加。
我可能不是在尋找代碼本身,而只是在終端中運行以添加必要的換行符(或某種編程或開發工具)。
爲了方便起見,將諾曼的答案轉換爲分離式單行程。
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