2011-11-03 30 views
12

Tôi có một thư mục có tên là foo. Foo có một số thư mục khác có thể có thư mục con và tệp văn bản. Tôi muốn tìm mọi tập tin bắt đầu với năm tên và đọc dòng thứ N của nó và in nó vào một tập tin mới. Ví dụ foo có một tệp gọi là year1 và các thư mục con có các tệp được gọi là year2, year3 v.v. Chương trình sẽ in dòng thứ 1 của year1 vào một tệp được gọi là writeout, sau đó nó sẽ in dòng thứ 2 của year2 vào tệp writeout, v.v.Làm cách nào để đọc dòng thứ N của một tệp và in nó vào một tệp mới?

Tôi cũng không thực sự hiểu cách thực hiện vòng lặp for cho một tệp.

Cho đến nay tôi có:

#!/bin/bash 

for year* in ~/foo 
do 
    Here I tried writing some code using the sed command but I can't think of something  else. 
done 

Tôi cũng nhận được một tin nhắn trong thiết bị đầu cuối mà nói 'năm *' không phải là một định danh hợp lệ. Bất kỳ ý tưởng nào?

+0

Ông có thể chấp nhận một trong những câu trả lời dưới đây như tôi tin rằng họ đã cung cấp đầy đủ thông tin cho câu hỏi này? –

Trả lời

0

Nhiệm vụ của bạn có hai nhiệm vụ phụ: Tìm tên của tất cả các tệp năm và sau đó trích xuất dòng thứ N. Hãy xem tập lệnh sau:

for file in `find foo -name 'year*'`; do 
    YEAR=`echo $file | sed -e 's/.*year\([0-9]*\)$/\1/'` 
    head -n $YEAR $file | tail -n 1 
done 

Cuộc gọi tìm thấy các tệp phù hợp với bạn trong thư mục foo. Dòng thứ hai chỉ trích các chữ số ở cuối tên tệp từ tên tệp. Dòng thứ ba sau đó chiết xuất N dòng đầu tiên từ tập tin, chỉ giữ lại dòng cuối cùng của N dòng đầu tiên (đọc: chỉ dòng thứ N).

+0

Tôi có thể thấy điều gì đó trên màn hình của mình không? Bởi vì tôi chỉ nhận được một dòng trống. – captain

5

Dưới đây là một cách để làm điều đó:

awk "NR==$YEAR" $file 
+0

Tôi nhận được thông báo: Dòng mới không mong đợi hoặc kết thúc chuỗi. – captain

+0

thì $ YEAR là một chuỗi rỗng hoặc không phải là số ... –

3

Sử dụng find để xác định vị trí các tập tin mà bạn muốn, và sau đó sed để trích xuất những gì bạn muốn:

find foo -type f -name year* | 
while read file; do 
    line=$(echo $file | sed 's/.*year\([0-9]*\)$/\1/') 
    sed -n -e "$line {p; q}" $file 
done 

Cách tiếp cận này:

  • Sử dụng find để tạo danh sách tệp có tên bắt đầu bằng w ith chuỗi "năm".
  • Ống danh sách tập tin vào một vòng lặp while để tránh dòng lệnh dài
  • Sử dụng sed để trích xuất số dòng mong muốn từ tên của tập tin
  • Sử dụng sed in chỉ đường cần thiết rồi ngay lập tức bỏ thuốc lá. (Bạn có thể bỏ qua q và chỉ cần viết ${line}p mà sẽ làm việc nhưng phải có khả năng kém hiệu quả của $file là lớn. Ngoài ra, q có thể không được hỗ trợ đầy đủ trên tất cả các phiên bản của sed.)

Nó sẽ không hoạt động đúng cho các tệp có dấu cách trong tên của chúng.

+0

Tôi nhận được thông báo nói: sed: -e expression # 1, char 7: lệnh không xác định: 'k ' – captain

+0

Bạn có thể ghi đè đầu ra của lệnh sau khi chạy hay không "set -x" để bật gỡ lỗi? –

+0

Xin lỗi nhưng tôi không hiểu tôi phải làm gì. Tôi là người mới bắt đầu. – captain

28

Sed có thể giúp bạn.

Hãy nhớ rằng sed thường xử lý tất cả các dòng trong một tệp VÀ in từng dòng trong tệp.

Bạn có thể tắt tính năng đó và chỉ có sed in các đường quan tâm bằng cách khớp mẫu hoặc số dòng.

Vì vậy, để in các dòng thứ 2 của tập 2, bạn có thể nói

sed -n '2p' file2 > newFile2 

Để in dòng thứ 2 và sau đó ngừng xử lý thêm các q (ví bỏ) lệnh (bạn cũng cần niềng răng vào nhóm 2 lệnh cùng nhau), tức là

sed -n '2{p;q;}' file2 > newFile2 

(nếu bạn đang xử lý tệp lớn, điều này có thể tiết kiệm thời gian).

Để làm cho điều đó hơn Nói chung, bạn có thể thay đổi số để một biến mà sẽ tổ chức một số, ví dụ:

lineNo=3 
    sed -n "${lineNo}{p;q;}" file3 > newFile3 

Nếu bạn muốn tất cả các dòng cắt của bạn để đi vào 1 file, sau đó sử dụng vỏ 'append-chuyển hướng', tức là

for lineNo in 1 2 3 4 5 ; do 
    sed -n "${lineNo}{p;q;}" file${lineNo} >> aggregateFile 
done 

các tin đăng khác, với việc sử dụng các kết quả của find ... lái xe filelist của bạn, là một cách tiếp cận tuyệt vời.

Tôi hy vọng điều này sẽ hữu ích.

+0

Cú pháp nhóm hoạt động trong GNU sed. –

+0

@glennjackman: không chắc chắn về quan điểm của bạn. nhóm cú pháp hoạt động trong sed trên AIX và solaris quá, và kiến ​​thức và niềm tin của tôi là một phần của thiết kế ban đầu của sed. Cảm ơn phản hồi :-) – shellter

+0

Nếu bạn thích Python trên sed bạn có thể làm ... 'python -c" import sys; print (sys.stdin.readlines() [int (sys.argv [1]) - 1]) .strip() "' (hoặc tất nhiên xác định bí danh cho điều lớn đó) – hangtwenty

0
1.time head -5 emp.lst tail -1 
It has taken time for execution is 
real 0m0.004s 
user 0m0.001s 
sys 0m0.001s 

or 

2.awk 'NR==5' emp.lst 
It has taken time for execution is 
real 0m0.003s 
user 0m0.000s 
sys 0m0.002s 

or 

3.sed -n '5p' emp.lst 
It has taken time for execution is 
real 0m0.001s 
user 0m0.000s 
sys 0m0.001s 

or 

4.using some cute trick we can get this with cut command 
cut -d “ 
“ -f 5 emp.lst 
# after -d press enter ,it means delimiter is newline 
It has taken time for execution is 
real 0m0.001s 
+1

Trong khi câu trả lời của bạn có thể giải quyết được câu hỏi, nó luôn tốt hơn nếu bạn có thể mô tả vấn đề là gì và cách trả lời câu trả lời . Đây là một gợi ý để tiếp tục cải thiện câu trả lời này và trong tương lai. –

+1

Bạn có thể giải thích cách câu trả lời của bạn hoạt động và hữu ích không? –

1

Cách tốt nhất mà luôn luôn làm việc, với điều kiện bạn cung cấp 2 đối số:

$ touch myfile 
$ touch mycommand 
$ chmod +x mycommand 
$ touch yearfiles 
$ find/-type f -name year* >> yearfiles 
$ nano mycommand 
$ touch foo 

Loại này:

#/bin/bash 
head -n $1 $2 >> myfile 
less -n 1 myfile >> foo 

Sử dụng ^X, y và tham gia để tiết kiệm. Sau đó chạy mycommand:

$ ./mycommand 2 yearfiles 
$ cat foo 
year2 

Giả year tập tin của bạn là:

year1, year2, year3 

Thêm vào đó, bây giờ bạn có cài đặt, bạn chỉ cần sử dụng $ ./mycommand LINENUMBER FILENAME từ bây giờ.

0

Ở đây bạn đi

sed ${index}'q;d' ${input_file} > ${output_file} 
Các vấn đề liên quan