2010-07-16 47 views
9

Tôi có một số lượng lớn các tệp nguồn mà tất cả đều thiếu một dòng mới ở cuối.Cách khắc phục cảnh báo “Không có dòng mới ở cuối tệp” cho nhiều tệp?

Làm cách nào để tự động thêm dòng mới vào cuối mỗi dòng?

Một số có thể đã có dòng mới, vì vậy chỉ nên thêm dòng mới nếu cần.

Có lẽ tôi không tìm mã, mỗi lần, nhưng chỉ là một thứ tôi có thể chạy trong Thiết bị đầu cuối để thêm các dòng mới cần thiết (hoặc một số loại công cụ lập trình hoặc phát triển).

Trả lời

3

Câu trả lời của Norman đã được chuyển đổi thành một lớp lót để thuận tiện.

for i in * ; do echo $i; \ 
if diff /dev/null "$i" | tail -1 | \ 
    grep '^\\ No newline' > /dev/null; then echo >> "$i"; \ 
fi; done 

Thay thế * với bất cứ mô hình tập tin mà bạn muốn, ví dụ như *.c

Và khác để chỉ cho bạn biết tập tin được chia nhỏ:

for i in * ; do \ 
if diff /dev/null "$i" | tail -1 | \ 
    grep '^\\ No newline' > /dev/null; then echo $i; \ 
fi; done 
+0

Không có giải pháp nào phù hợp với tôi –

+1

Nếu bạn muốn nó theo cách đệ quy, bạn có thể hoán đổi '*' với '$ (find. -type f)' hoặc '$ (tìm -type f -name )' – durron597

7

Nếu bạn có quyền truy cập vào các công cụ Unix, bạn có thể chạy diff để tìm kiếm những file thiếu một dòng mới và sau đó nối nó:

#!/bin/sh 
for i 
do 
    if diff /dev/null "$i" | tail -1 | grep '^\\ No newline' > /dev/null 
    then 
    echo >> "$i" 
    fi 
done 

Tôi dựa vào diff để tạo ra thông điệp với một \ trong cột đầu tiên, tail để cho tôi dòng cuối cùng của đầu ra của diffgrep để cho tôi biết nếu dòng cuối cùng là thư tôi đang tìm kiếm. Nếu tất cả đều hoạt động, khi đó echo sẽ tạo dòng mới và >> sẽ thêm nó vào tệp "$i". Các dấu ngoặc kép xung quanh "$i" đảm bảo mọi thứ vẫn hoạt động nếu tên tệp có dấu cách trong đó.

+2

Không tệ, nhưng grep trả về một thư được bản địa hóa, như "\ Brak znaku nowej linii (v.v.)". Bên cạnh đó, các diff ra toàn bộ tập tin. Tôi muốn sử dụng 'đuôi -1 $ f | grep '\ n'' cho điều kiện (hoạt động trên hộp của tôi). –

+0

@TomaszGandor: 'đuôi -1 tên tệp | grep '\ n' dường như luôn trả về kết quả sai trên mac của tôi bất kể có dấu dòng mới hay không. – Gino

2

OK, sau khi phàn nàn trong các ý kiến, có giải pháp tốt hơn của tôi. Trước tiên, bạn muốn biết, các tập tin bị thiếu dòng mới:

find -type f -exec sh -c "tail -1 {} | xxd -p | tail -1 | grep -v 0a$" ';' -print 

Không siêu nhanh (gọi một vài quy trình cho mỗi tập tin), nhưng đó là OK để sử dụng thực tế.

Bây giờ, khi bạn có nó, bạn cũng có thể thêm các dòng mới, với -exec khác:

find -type f -exec sh -c "tail -1 {} | xxd -p | tail -1 | grep -v 0a$" ';' -exec sh -c "echo >> {}" ';' 

gotchas có thể:

  • nếu tên tập tin là xấu, ví dụ họ có không gian, bạn có thể cần tail -1 \"{}\". Hoặc bạn có tìm thấy đúng không?

  • bạn có thể muốn thêm nhiều bộ lọc để tìm, như -name \*py hoặc các loại tương tự.

  • suy nghĩ về các dòng mới có thể DOS/Unix lộn xộn trước khi sử dụng (sửa lỗi đầu tiên).

EDIT:

Nếu bạn không thích các đầu ra từ các lệnh này (lặp lại một số hex), thêm -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 >> {}" ';' 
+1

Đây là * quá lớn * quá mức cần thiết. – tripleee

0

Do Để huy nội địa hóa Tim và Norman câu trả lời Sẽ được cải thiện bằng cách sử dụng tiền tố 'LANG = C' để có cơ hội khớp mẫu 'Không có dòng mới' với mọi hệ thống có bất kỳ tham số vùng nào

Điều này đảm bảo dòng trống cuối cho mỗi tập tin đưa vào dòng lệnh của kịch bản này:

#!/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 

Và kịch bản này phát hiện file thiếu của nó:

#!/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 
1

Thử cũ chiều:

ex -s +"bufdo wq" *.c 

Và đệ quy (với a new globbing option được bật):

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

Điều này tương đương với vi -es. Thay đổi *.c để gia hạn quyền lợi của bạn.

ex/vi sẽ tự động nối thêm dòng mới khi lưu nếu không có.

0

Sau khi tìm công cụ thực hiện công việc này mà không có may mắn. Tôi quyết định viết của riêng tôi

Đây là kịch bản python của tôi để làm công việc đó

Nó chỉ thêm những (\ r \ n) để nộp không chứa (\ n) ở phần cuối của tập tin

https://github.com/tranhuanltv/append_newline

Cách sử dụng: ./projects .c append_newline.py ./result_dir

Các yêu cầu Make Kéo nếu bạn muốn

+0

Điều này rất có vấn đề - tìm kiếm -1 từ END là OK, nhưng bạn có thể dễ dàng kết hợp các dòng mới Unix và DOS theo cách này ... –

0

tôi ngạc nhiên không ai đã đề cập rằng nhiều công cụ xử lý văn bản đơn giản như Awk sẽ thêm một dòng mới làm hiệu ứng phụ. Đây là một vòng lặp đơn giản sẽ ghi đè lên một tập tin chỉ khi một dòng mới đã được thêm vào.

for f in *; do 
    awk 1 "$f" >tmp 
    cmp -s tmp "$f" || mv tmp "$f" 
done 
rm -f tmp 

(Tệp tạm thời rõ ràng là hơi bị mụn cóc.)

IDEone demo: http://ideone.com/HpRHcx

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

Có một vài bước liên quan như:

  1. đệ quy tìm file
  2. Phát hiện những file thiếu một dòng mới trailing
  3. Vòng hơn so với từng những tệp đó
  4. Nối dòng mới

Bước 1 truyền thống thực hiện với find (theo truyền thống Unix của "mỗi công cụ làm một điều và làm nó tốt"), nhưng kể từ khi pcregrep đã hỗ trợ dựng sẵn, tôi cảm thấy thoải mái sử dụng nó. Tôi cẩn thận để tránh rối tung xung quanh với thư mục .git.

Bước 2 được thực hiện với một biểu thức chính quy multiline phù hợp với file làm có một dòng mới cuối cùng, và in tên của file mà không trận đấu.

Bước 3 được thực hiện với vòng lặp while/read thay vì cho/in, vì sau này không thành công cho tên tệp có không gian và danh sách tệp cực dài.

Bước 4 là một tiếng vang đơn giản, theo cách tiếp cận của @ norman-ramsey.

h/t @ anthony-bush https://stackoverflow.com/a/20687956/577438 cho đề xuất pcregrep.

1

Tôi đang sử dụng find thay vì for f in * vì nó là đệ quy và các câu hỏi về "số lượng lớn các file nguồn".

Tôi đang sử dụng while read thay vì find -exec hoặc xargs vì lý do hiệu suất, nó giúp tiết kiệm quá trình vỏ sinh sản mỗi lần.

Tôi đang lợi dụng thực tế là toán tử backtick đang trả về kết quả đầu ra của lệnh "với bất kỳ dòng mới nào bị xóa" man bash, do đó, cho các tệp bị chấm dứt đúng cách sẽ bị trống và tiếng vọng sẽ bị bỏ qua.

Cặp đôi find | read sẽ thất bại trên tên tệp chứa ký tự dòng mới, nhưng nó dễ dàng để sửa chữa nếu cần thiết:

find -type f -print0 | while read -d $'\0' f; do [[ `tail -c1 "$f"` ]] && echo >> "$f"; done

0

Dưới đây là giải pháp bash kịch bản của tôi. Đầu tiên nó kiểm tra xem tệp có phải là tệp văn bản hay không. Sau đó, nếu đó là một tập tin văn bản, nó sử dụng đuôi và od (bát phân bát) để xem ký tự cuối cùng có phải là ký tự dòng mới hay không.Nếu không, thì nó sẽ thêm một dòng mới bằng cách sử dụng tiếng vọng:

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 
1

Sửa lỗi đơn giản cho các tệp "thiếu" dòng mới ở cuối tệp đơn giản là sed; các bản sửa lỗi sau khi tập tin "tại chỗ" (sử dụng tùy chọn "-i"):

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

Giải thích: tìm tất cả các file (-type f), chạy sed, thay đổi các tập tin tại chỗ (-i), được đưa ra đoạn mã/biểu thức sau (-e), khớp với phần cuối của tệp ($) và thực hiện tác vụ "chắp thêm" (a\), nhưng không thực sự chỉ định bất kỳ văn bản nào để nối thêm (không có gì sau số \) đang diễn ra để thêm một dòng mới vào cuối tệp, nhưng chỉ khi nó bị thiếu. In tất cả các tập tin tìm thấy (cố định hay không), có lẽ là không cần thiết.

Thông báo chính là sed các tính năng khác nhau trên các nền tảng, do đó, -i-e có thể hoặc không được hỗ trợ/giống nhau; ví dụ. Unix cũ hơn hoặc các kỳ quặc MacOS có thể yêu cầu cú pháp hơi khác một chút.

Các vấn đề liên quan