2011-01-07 38 views
17

Tôi làm cách nào để liệt kê văn bản thông thường (.txt) tên tệp không kết thúc bằng dòng mới?Làm cách nào để liệt kê các tệp không kết thúc bằng dòng mới?

ví dụ .: danh sách (đầu ra) filename này:

$ cat a.txt 
asdfasdlsad4randomcharsf 
asdfasdfaasdf43randomcharssdf 
$ 

và không danh sách (đầu ra) filename này:

$ cat b.txt 
asdfasdlsad4randomcharsf 
asdfasdfaasdf43randomcharssdf 

$ 
+0

Bạn có đang tìm kiếm một màn hình rộng các tệp tạo thành một thư mục không? Câu hỏi của bạn không rõ ràng bằng ví dụ trên .. – James

+2

"txt bình thường" có nghĩa là gì? Bạn đang nói về các tệp kết thúc bằng một dòng * trống * (\ n \ n) hoặc chỉ các tệp kết thúc bằng một dòng mới? Bạn có thể sử dụng 'od -c filename' để in đại diện rõ ràng của tập tin. – jfs

+1

Chỉ cần nhấn mạnh: dòng mới là * không * giống như dòng * trống *. Một dòng mới là một ký tự đơn - nó phân định những gì chúng ta thấy là "dòng". Một dòng trống chỉ đơn giản là một "dòng" không có ký tự, thường là 2 ký tự dòng mới liên tiếp không có gì ở giữa hoặc dòng đầu tiên trong tệp bắt đầu bằng dòng mới. Một số người gọi đường dây chỉ bao gồm khoảng trắng "khoảng trắng" và đặt cụm từ "dòng trống" cho 2 ký tự dòng mới liên tiếp. Bạn nên rõ ràng về những gì bạn muốn. – jw013

Trả lời

2

Đây là kludgy; ai đó chắc chắn có thể làm tốt hơn:

for f in `find . -name '*.txt' -type f`; do 
    if test `tail -c 1 "$f" | od -c | head -n 1 | tail -c 3` != \\n; then 
     echo $f; 
    fi 
done 

N.B. điều này trả lời câu hỏi trong tiêu đề, khác với câu hỏi trong phần nội dung (tìm kiếm các tệp kết thúc bằng \ n \ n tôi nghĩ).

2

này nên làm như lừa:

#!/bin/bash 

for file in `find $1 -type f -name "*.txt"`; 
do 
     nlines=`tail -n 1 $file | grep '^$' | wc -l` 
     if [ $nlines -eq 1 ] 
       then echo $file 
     fi 
done; 

Gọi nó theo cách này: ./script dir

Ví dụ: ./script /home/user/Documents/ -> liệt kê tất cả các tệp văn bản trong số /home/user/Documents kết thúc bằng \n.

+0

Cải tiến đầu tiên là đặt 'IFS = $ '\ n'' trước đó. Nó cho phép để xử lý các tập tin với không gian. Cải tiến thứ hai là thay thế '$ nlines -eq 1' bằng' $ nlines -eq 0' vì tác giả cần "tên tệp, ** không kết thúc ** bằng dòng mới". –

7

này cung cấp cho một thử:

find -type f -exec sh -c '[ -z "$(sed -n "\$p" "$1")" ]' _ {} \; -print 

Nó sẽ in tên tập tin các tập tin kết thúc bằng một dòng trống. Để in các tệp không kết thúc bằng một dòng trống, hãy thay đổi -z thành -n.

+1

Câu trả lời sử dụng 'cho ... tìm ... do' sẽ thất bại nếu có tên tệp có chứa dấu cách. –

+1

bạn đúng về 'cho .. tìm .. 'http://mywiki.wooledge.org/BashPitfalls#for_i_in_.24.28ls_.2A.mp3.29 – jfs

+1

Giải pháp tuyệt vời. Đề nghị bạn không echo như một phần của kịch bản 'sh' và thêm' -print' vào cuối lệnh find. Sau đó, '-print' có thể được sửa đổi thành bất cứ điều gì là cần thiết (ví dụ:' -print0'). – squid314

1

Một lựa chọn khác:

$ find . -name "*.txt" -print0 | xargs -0I {} bash -c '[ -z "$(tail -n 1 {})" ] && echo {}' 
+0

Cảm ơn bạn rất nhiều, đây là ví dụ duy nhất trong chủ đề này thực sự hoạt động (trên OSX) –

+0

... thực sự, điều này dường như không tìm đúng tệp –

0

Kể từ câu hỏi của bạn có thẻ perl, tôi sẽ đăng một câu trả lời mà sử dụng nó:

find . -type f -name '*.txt' -exec perl check.pl {} + 

nơi check.pl như sau:

#!/bin/perl 

use strict; 
use warnings; 

foreach (@ARGV) { 
    open(FILE, $_); 

    seek(FILE, -2, 2); 

    my $c; 

    read(FILE,$c,1); 
    if ($c ne "\n") { 
     print "$_\n"; 
    } 
    close(FILE); 
} 

Kịch bản perl này chỉ mở, mỗi lần, các tệp được truyền dưới dạng tham số và chỉ đọc ký tự tiếp theo đến cuối; nếu nó không phải là một ký tự dòng mới, nó chỉ in ra tên tập tin, nếu không nó sẽ không làm gì cả.

+0

Điều gì sẽ xảy ra nếu ký tự cuối không phải là dòng mới (tất nhiên là nó không phải là một tập tin văn bản hợp lệ)? –

17

Sử dụng pcregrep, một Perl Tương thích Regular Expressions phiên bản của grep mà hỗ trợ chế độ nhiều dòng sử dụng cờ -M có thể được sử dụng để phù hợp (hoặc không phù hợp) nếu dòng cuối cùng có một dòng mới:

pcregrep -LMr '\n$' . 

Trong ví dụ trên, chúng tôi đang nói tìm kiếm đệ quy (-r) trong thư mục hiện tại (.) liệt kê các tệp không khớp (-L) regex đa cấp (-M) của chúng tôi để tìm dòng mới ở cuối tệp ('\n$')

Thay đổi -L đến -l sẽ liệt kê các tệp mà làm có dòng mới trong đó.

+0

Tôi nên chỉ ra rằng câu trả lời được đưa ra bởi @ dennis-williamson cũng không thành công đối với các tệp có không gian trong đó. Ít nhất là nó đã làm cho tôi. –

+0

Tôi đã thêm một tập hợp các trích dẫn bị thiếu trong câu trả lời của mình nên giải quyết vấn đề đó. –

+1

Chỉ cần một lưu ý cho người đọc trong tương lai: lệnh pcregrep này là chính xác cho các tệp có * không * chứa các dòng trống. Counterexample: 'printf '\ n \ nb" | pcregrep -M '\ n $' -' sẽ in 'a' (và do đó chạy với' -L' sẽ không in được gì). – maverickwoo

14

Ok tới lượt tôi, tôi cung cấp cho nó một thử:

find -type f -print0 | xargs -0 -L1 bash -c 'test "$(tail -c 1 "$0")" && echo "No new line at end of $0"' 
1

Ví dụ này làm việc cho tôi trên OSX (nhiều các giải pháp trên không)

for file in `find . -name "*.java"` 
do 
    result=`od -An -tc -j $(($(ls -l $file | awk '{print $5}') - 1)) $file` 
    last_char=`echo $result | sed 's/ *//'` 
    if [ "$last_char" != "\n" ] 
    then 
    #echo "Last char is .$last_char." 
    echo $file 
    fi 
done 
3

Nếu bạn đang sử dụng ' ack '(http://beyondgrep.com) thay thế cho grep, bạn chỉ cần chạy điều này:

ack -v '\n$' 

Nó thực sự tìm kiếm tất cả các dòng không khớp (-v) một dòng mới ở cuối dòng.

+1

Giải pháp đơn giản, dễ dàng. Thêm '-l' để chỉ nhận các tệp phù hợp chứ không phải dòng. – stu42j

1

Hầu hết các giải pháp trên trang này không hoạt động đối với tôi (FreeBSD 10.3 amd64). giải pháp OSX Ian Will làm gần như luôn luôn làm việc, nhưng là khá khó theo dõi: - (

Có một giải pháp dễ dàng mà hầu-luôn luôn làm việc quá: (nếu $ f là tập tin):

sed -i '' -e '$ a \' "$ f"

có một vấn đề lớn với các giải pháp sed:. nó không bao giờ mang đến cho bạn cơ hội để chỉ cần kiểm tra (và không thêm một dòng mới)

Cả hai giải pháp trên đều thất bại đối với các tệp DOS. Tôi cho rằng giải pháp di động/scriptable nhất có thể là ably là đơn giản nhất, mà tôi đã tự phát triển bản thân mình: -)

Đây là tập lệnh sh sơ cấp kết hợp tệp/unix2dos/đuôi. Trong sản xuất, bạn có thể sẽ cần phải sử dụng "$ f" trong dấu ngoặc kép và lấy đuôi ra (nhúng vào biến vỏ tên cuối cùng) là \ "$ f \"

if file $f | grep 'ASCII text' > /dev/null; then 
    if file $f | grep 'CRLF' > /dev/null; then 
     type unix2dos > /dev/null || exit 1 
     dos2unix $f 
     last="`tail -c1 $f`" 
     [ -n "$last" ] && echo >> $f 
     unix2dos $f 
    else 
     last="`tail -c1 $f`" 
     [ -n "$last" ] && echo >> $f 
    fi 
fi 

Hope this helps một ai đó.

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