2009-12-25 36 views
33

Tôi muốn chạy lệnh system trong tập lệnh awk và nhận được kết quả đầu ra được lưu trữ trong một biến. Tôi đã cố gắng để làm điều này, nhưng đầu ra của lệnh luôn luôn đi vào vỏ và tôi không thể nắm bắt nó. Bất kỳ ý tưởng về cách này có thể được thực hiện?Gán đầu ra của lệnh hệ thống thành biến

Ví dụ:

$ date | awk --field-separator=! {$1 = system("strip $1"); /*more processing*/} 

nên gọi lệnh strip hệ thống và thay vì gửi đầu ra vào vỏ, nên gán sản lượng trở lại $1 để chế biến nhiều hơn nữa. Rignt bây giờ, nó gửi đầu ra đến shell và gán mã của lệnh vào $1.

+1

nit: Sản lượng sẽ không vỏ, nó sẽ đến nhà ga/console. Shell không đọc bất kỳ đầu ra nào của con của nó - chúng chỉ chia sẻ các bộ mô tả tập tin được liên kết với cùng một tty. –

Trả lời

23

Đã tìm ra.

Chúng tôi sử dụng awk của Two-way I/O

{ 
    "strip $1" |& getline $1 
} 

đi $ 1 dải và getline mất đầu ra từ dải trở lại $ 1

+1

Nếu bạn cần gọi cùng một lệnh nhiều lần, chúng ta phải đóng lệnh (http://www.staff.science.uu.nl/~oostr102/docs/nawk/nawk_26.html#SEC29) – mcoolive

49

Lưu ý: Coprocess là GNU awk cụ thể. Dù sao thay thế khác là sử dụng getline

cmd = "strip "$1 
while ((cmd | getline result) > 0) { 
    print result 
} 
close(cmd) 
+0

Cảm ơn bạn. Bằng cách này, tôi có thể xóa & khỏi câu trả lời của tôi. Trông mát hơn. Nhưng tôi đang viết chỉ để sử dụng trong Linux, do đó, không có sẵn của diều hâu không phải là một vấn đề? – Sahas

+0

có, không phải là một vấn đề. bạn vẫn nên kiểm tra tài liệu và xem liệu coprocess chỉ có sẵn trong phiên bản gawk nhất định hay không. tôi không thể nhớ trên đầu của tôi – ghostdog74

+0

Từ phiên bản 3.1. RedHat có 3.1.5. Dù sao tôi sẽ sử dụng cách bạn đề nghị, trừ khi tôi muốn gửi một cái gì đó để stdin của lệnh, trong đó trường hợp coprocess là hữu ích. – Sahas

5
gawk '{dt=substr($4,2,11); gsub(/\//," ",dt); "date -d \""dt"\" +%s"|getline ts; print ts}' 
+13

Nếu bạn đăng câu trả lời, bạn nên giải thích các phần khác nhau (những gì bạn đã làm và tại sao nó hoạt động). Vì vậy, những người khác có thể học hỏi từ câu trả lời của bạn. Đối với một số người, dòng này sẽ tự giải thích. Nhưng đối với những người khác thật khó để làm theo những gì bạn đã làm chính xác. –

16

Để chạy một lệnh hệ thống trong awk bạn có thể sử dụng system() hoặc cmd | getline.

tôi thích cmd | getline vì nó cho phép bạn nắm bắt những giá trị vào một biến:

$ awk 'BEGIN {"date" | getline mydate; close("date"); print "returns", mydate}' 
returns Thu Jul 28 10:16:55 CEST 2016 

Tổng quát hơn, bạn có thể đặt lệnh vào một biến:

awk 'BEGIN { 
     cmd = "date -j -f %s" 
     cmd | getline mydate 
     close(cmd) 
    }' 

Lưu ý điều quan trọng là sử dụng close() để tránh bị lỗi "tạo quá nhiều tệp mở" nếu bạn có nhiều kết quả (cảm ơn mateuscb để chỉ ra điều này trong nhận xét).


Sử dụng system(), sản lượng lệnh được in tự động và giá trị mà bạn có thể bắt là mã trả về:

$ awk 'BEGIN {d=system("date"); print "returns", d}' 
Thu Jul 28 10:16:12 CEST 2016 
returns 0 
$ awk 'BEGIN {d=system("ls -l asdfasdfasd"); print "returns", d}' 
ls: cannot access asdfasdfasd: No such file or directory 
returns 2 
+2

+1 để thêm 'close()', nếu bạn không thêm nó và có nhiều kết quả, bạn có thể nhận được "tạo quá nhiều tệp mở". Nếu bạn có lệnh dài hơn, bạn có thể thực hiện 'cmd =" ​​date -j -f% s "; cmd | getline mydate; đóng (cmd) ' – mateuscb

+1

@mateuscb cảm ơn rất nhiều vì phản hồi của bạn. Tôi đã cập nhật câu hỏi để bao gồm các nhận xét hữu ích của bạn. – fedorqui

+1

Cảm ơn bạn đã nhắc nhở lệnh close(). Nó giúp rất nhiều. Mà không đặt gần(), đôi khi tôi nhận được kết quả ngày sai cho nhiều kết quả. Với việc đóng(). kết quả nhiều ngày của tôi được hiển thị chính xác. – csu007

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