Xem qua một tập tin và in văn bản từ các dòng cụ thể


8

Tôi có một tập tin với dữ liệu mà tôi lưu. Bây giờ tôi muốn in kết quả của mình vào một tệp mới.

Ví dụ: hãy lấy ví dụ này randomlog.log:

Link encap:Ethernet HWaddr 08:00:00:00:00:67
inet addr:10.10.10.10 Bcast:10.10.10.10 Mask:255.255.255.0
inet6 addr: fe80::casf:sdfg:23ra:dg12/64 Scope:Link

Làm cách nào tôi chỉ có thể lấy dữ liệu từ ký tự thứ 12 đến thứ 20 của dòng đầu tiên và sau đó là ký tự thứ 4 đến thứ 8 của dòng thứ 3? Đầu ra sẽ trông giống như thế này:

Ethernet
t6 ad

Điều này có thể không? Tôi muốn đặt dòng và từ vị trí đến vị trí này.

Câu trả lời:


9

Đây là một sedcách tiếp cận:

$ sed -nE '1s/.{11}(.{8}).*/\1/p; 3s/.{3}(.{4}).*/\1/p' file  
Ethernet
t6 a

Giải trình

Việc -nchặn đầu ra bình thường (thông thường là in mọi dòng đầu vào) để nó chỉ in khi được yêu cầu. Cho -Ephép mở rộng các biểu thức thông thường.

Các sedkịch bản có hai lệnh, cả hai đều sử dụng toán tử thay thế ( s/original/replacement/). Di 1s/.{11}(.{8}).*/\1/pchúc chỉ chạy trên dòng thứ nhất (đó là những gì 1snó làm) và sẽ khớp với 11 ký tự đầu tiên của dòng ( .{11}), sau đó nó bắt 8 số tiếp theo ( (.{8}), dấu ngoặc đơn là một "nhóm bắt giữ") và sau đó mọi thứ khác cho đến khi cuối dòng ( .*). Tất cả điều này được thay thế bằng bất cứ thứ gì trong nhóm bắt giữ ( \1; nếu có nhóm bắt giữ thứ hai, nó sẽ là \2v.v.). Cuối cùng, pở cuối ( s/foo/bar/p) làm cho dòng được in sau khi thay thế đã được thực hiện. Điều này dẫn đến chỉ có 8 ký tự được xuất ra.

Lệnh thứ hai là cùng một ý tưởng chung ngoại trừ việc nó sẽ chỉ chạy trên dòng thứ 3 ( 3s) và sẽ giữ 4 ký tự bắt đầu từ dòng thứ 4.


Bạn cũng có thể làm điều tương tự với perl:

$ perl -ne 'if($.==1){s/.{11}(.{8}).*/\1/}
            elsif($.==3){s/.{3}(.{4}).*/\1/}
            else{next}; print; ' file 
Ethernet
t6 a

Giải trình

-nenghĩa là "đọc dòng tệp đầu vào theo dòng và áp dụng tập lệnh được cung cấp -echo từng dòng. Tập lệnh là ý tưởng cơ bản giống như trước. $.Biến giữ số dòng hiện tại để chúng tôi kiểm tra xem số dòng có phải 1hay không 3, và vì vậy, chạy thay thế, bỏ qua khác. Do đó, printsẽ chỉ được chạy cho hai dòng đó vì tất cả các dòng khác sẽ bị bỏ qua.


Tất nhiên, đây là Perl, vì vậy TIMTOWTDI :

$ perl -F"" -lane '$. == 1 && print @F[11..19]; $.==3 && print @F[3..6]' file 
Ethernet 
t6 a

Giải trình

Ở đây, -aphương tiện "phân tách từng dòng đầu vào trên ký tự được cung cấp bởi -Fvà lưu thành mảng @F. Vì ký tự được cung cấp trống, điều này sẽ lưu từng ký tự của dòng đầu vào dưới dạng một phần tử @F. Sau đó, chúng tôi in các phần tử 11-19 ( mảng bắt đầu đếm tại 0) cho dòng thứ 1 và thứ 3 cho dòng thứ 3.


1

phương pháp tiếp cận:

$ awk 'NR==1{print substr($0,12,8)};NR==3{print substr($0,4,4)}' input.txt  
Ethernet
t6 a

Sử dụng NRđể xác định số dòng (theo thuật ngữ awk - bản ghi) và theo đó in chuỗi con của dòng. substr()chức năng ở định dạng

substr(string,starting position,how much offset) 

Con trăn

$ python -c 'import sys                                                                                                                                                
> for index,line in enumerate(sys.stdin,1):                                                                                                                            
>     if index == 1:
>          print line[11:19]
>     if index == 3:
>          print line[3:7]' < input.txt
Ethernet
t6 a

Điều này sử dụng <toán tử shell để chuyển hướng luồng đầu vào sang quá trình python từ tệp đầu vào. Lưu ý rằng các chuỗi trong python được lập chỉ mục 0, do đó bạn cần thay đổi tất cả các số ký tự mong muốn của mình bằng 1.

cách vỏ di động

Này hoạt động trong ksh, dash, bash. Chỉ dựa vào tiện ích vỏ, không có gì bên ngoài.

#!/bin/sh

rsubstr(){
    i=0;
    while [ $i -lt  $2 ];
    do
        rmcount="${rmcount}?"
        i=$(($i+1))
    done;
    echo "${1#$rmcount}"
}

lsubstr(){
    printf "%.${2}s\n" "$1"
}

line_handler(){
    case $2 in
        1) lsubstr "$(rsubstr "$1" 11)" 8 ;;
        3) lsubstr "$(rsubstr "$1" 3)" 5 ;;
    esac
}

readlines(){
    line_count=1
    while IFS= read -r line;
    do
        line_handler "$line" "$line_count"
        line_count=$(($line_count+1))
    done < $1
}

readlines "$1"

Và nó hoạt động như vậy:

$ ./get_line_substrings.sh input.txt                                                                                                                                   
Ethernet
t6 ad
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.