bash echo số dòng của tệp được cung cấp trong một biến bash không có tên tệp


79

Tôi có ba cấu trúc sau trong một tập lệnh bash:

NUMOFLINES=$(wc -l $JAVA_TAGS_FILE)
echo $NUMOFLINES" lines"

echo $(wc -l $JAVA_TAGS_FILE)" lines"

echo "$(wc -l $JAVA_TAGS_FILE) lines"

Và cả hai đều tạo ra đầu ra giống hệt nhau khi chạy tập lệnh:

121711 /home/slash/.java_base.tag lines
121711 /home/slash/.java_base.tag lines
121711 /home/slash/.java_base.tag lines

Tức là tên của tệp cũng bị lặp lại (mà tôi không muốn). Tại sao các tập lệnh này không thành công và làm cách nào để xuất một tệp sạch:

121711 lines

?


Câu trả lời:


157

Ví dụ về sử dụng dữ liệu của riêng bạn

Bạn có thể tránh nhúng tên tệp của mình vào biến NUMOFLINES bằng cách sử dụng chuyển hướng từ JAVA_TAGS_FILE , thay vì chuyển tên tệp làm đối số cho wc . Ví dụ:

NUMOFLINES=$(wc -l < "$JAVA_TAGS_FILE")

Giải thích: Sử dụng Pipes hoặc Redirection để tránh tên tệp trong đầu ra

Các wc tiện ích sẽ không in tên của các tập tin trong sản lượng của nó nếu đầu vào được lấy từ một nhà điều hành đường ống hoặc chuyển hướng. Hãy xem xét các ví dụ khác nhau sau:

# wc shows filename when the file is an argument
$ wc -l /etc/passwd
41 /etc/passwd

# filename is ignored when piped in on standard input
$ cat /etc/passwd | wc -l
41

# unusual redirection, but wc still ignores the filename
$ < /etc/passwd wc -l
41

# typical redirection, taking standard input from a file
$ wc -l < /etc/passwd
41

Như bạn có thể thấy, lần duy nhất wc sẽ in tên tệp là khi nó được truyền dưới dạng đối số, thay vì dữ liệu trên đầu vào chuẩn. Trong một số trường hợp, bạn có thể muốn tên tệp được in, vì vậy sẽ rất hữu ích khi hiểu khi nào nó sẽ được hiển thị.


1
Hãy cẩn thận rằng cách tiếp cận này sẽ không bao gồm dòng cuối cùng nếu dòng cuối cùng không kết thúc bằng ký tự cuối dòng. Xem bản sửa lỗi của tôi bên dưới.
ling

15

wc không thể lấy tên tệp nếu bạn không cung cấp cho nó.

wc -l < "$JAVA_TAGS_FILE"

2
Vậy thì đừng. Chỉ cần chuyển tập tin vào wcstdin như được hiển thị trong câu trả lời. Vì vậy, cat "$JAVA_TAGS_FILE" | wc -lhoặc tương đương wc -l < "$JAVA_TAGS_FILE",. Bằng cách này, wcchỉ lấy dữ liệu thô chứ không phải tên tệp.
Witiko

12

Bạn cũng có thể sử dụng awk:

awk 'END {print NR,"lines"}' filename

Hoặc là

awk 'END {print NR}' filename


5

(áp dụng trên Mac và có thể là các Unix khác)

Trên thực tế, có một vấn đề với cách tiếp cận wc: nó không tính dòng cuối cùng nếu nó không kết thúc bằng ký hiệu cuối dòng.

Sử dụng cái này thay thế

nbLines=$(cat -n file.txt | tail -n 1 | cut -f1 | xargs)

hoặc thậm chí tốt hơn (cảm ơn gniourf_gniourf):

nblines=$(grep -c '' file.txt)

Lưu ý: Cách tiếp cận awk của chilicuil cũng hoạt động.


2
Phương pháp rất phức tạp! Có thể bạn sẽ muốn nblines=$(grep -c '' file)thay thế (đó là cách thông thường để đếm các dòng không đầy đủ trong trường hợp này). Lưu ý rằng theo POSIX, bạn đang đếm các dòng chưa hoàn chỉnh (chứ không phải các dòng ). Trên thực tế, bạn đang xử lý tệp nhị phân chứ không phải tệp văn bản .
gniourf_gniourf

@gniourf_gniourf Cảm ơn, tôi không biết về điều đó, nó hoạt động tuyệt vời và thậm chí còn ngắn gọn hơn.
ling

nó có thể là giải pháp tốt hơnnblines=$(($(cat "file.txt" | wc -l) + 1))
Andrey Izman

3

Nó rất đơn giản:

NUMOFLINES=$(cat $JAVA_TAGS_FILE | wc -l )

hoặc là

NUMOFLINES=$(wc -l $JAVA_TAGS_FILE | awk '{print $1}')

Đầu tiên là việc sử dụng mèo vô ích.
kap

@kap Không, nó chỉ trông như thế này. Nếu bạn loại bỏ cat, bạn sẽ có ví dụ thứ 2 sau đó vì wc -ltrả về 2 cột khi nó chỉ được sử dụng với một tệp.
Slava Semushin

-3

Tôi thường sử dụng tính năng 'đánh dấu quay lại' của bash

export NUM_LINES=`wc -l filename`

Lưu ý 'tick' là 'back tick', ví dụ: không phải là dấu nháy đơn bình thường


5
Đó chỉ là một ký hiệu khác và không giải quyết được vấn đề tên tệp là một phần của kết quả.
Izzy
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.