Làm thế nào để hợp nhất và kết quả đường ống từ hai lệnh khác nhau thành một lệnh?


35

Tôi muốn đầu ra hợp nhất (union) từ hai lệnh khác nhau và chuyển chúng thành một lệnh duy nhất.

Một ví dụ ngớ ngẩn:

Các lệnh tôi muốn hợp nhất đầu ra:

cat wordlist.txt
ls ~/folder/*

vào:

wc -l

Trong ví dụ này, nếu wordlist.txt chứa 5 dòng và 3 tệp, tôi muốn wc -ltrả về 8.

$cat wordlist.txt *[magical union thing]* ls ~/folder/* | wc -l
8

Làm thế nào để làm điều đó?

Câu trả lời:


56

Thứ kết hợp phép thuật của bạn là một dấu chấm phẩy ... và dấu ngoặc nhọn:

    { cat wordlist.txt ; ls ~/folder/* ; } | wc -l

Các dấu ngoặc nhọn chỉ nhóm các lệnh lại với nhau, do đó dấu hiệu đường ống |ảnh hưởng đến đầu ra kết hợp.

Bạn cũng có thể sử dụng dấu ngoặc đơn ()xung quanh một nhóm lệnh, sẽ thực thi các lệnh trong một lớp con. Điều này có một tập hợp khác biệt tinh tế với dấu ngoặc nhọn, ví dụ: thử cách sau:

    cd $HOME/Desktop ; (cd $HOME ; pwd) ; pwd
    cd $HOME/Desktop ; { cd $HOME ; pwd ; } ; pwd

Bạn sẽ thấy rằng tất cả các biến môi trường, bao gồm thư mục làm việc hiện tại, được đặt lại sau khi thoát khỏi nhóm dấu ngoặc đơn, nhưng không phải sau khi thoát khỏi nhóm dấu ngoặc nhọn.

Đối với dấu chấm phẩy, các lựa chọn thay thế bao gồm &&||các dấu hiệu, sẽ chỉ thực hiện một cách có điều kiện lệnh thứ hai nếu lần đầu tiên thành công hoặc nếu không, ví dụ,

    cd $HOME/project && make
    ls $HOME/project || echo "Directory not found."

1
Đó là công việc! Giúp tôi tìm hiểu - chính xác những cái niềng răng đang làm gì ở đây? Họ có sức mạnh ma thuật nào khác?
David Oneill

@DavidOneill { list; }là một lệnh ghép . From bash(1): list được thực hiện đơn giản trong môi trường shell hiện tại. danh sách phải được chấm dứt bằng một dòng mới hoặc dấu chấm phẩy. [..] Trạng thái trả về là trạng thái thoát của danh sách.
Lekensteyn

Tôi đã thêm một chút thông tin vào câu trả lời. Hướng dẫn dứt khoát cho shell scripting với bash là trang bash, gõ man bashtừ dòng lệnh và duyệt nó.
pottaomme

nên ; trong các lệnh đó không phải là && trong trường hợp tệp wordlist.txt không tồn tại?
Rinzwind

Nếu wordlist.txtkhông tồn tại một lỗi từ catsẽ xuất hiện trên lỗi tiêu chuẩn, nhưng không xuất hiện trên đầu ra tiêu chuẩn, do đó wc -lsẽ không tính bất kỳ dòng nào từ nó. Tương tự ~/folderkhông tồn tại. Người ta có thể thêm 2> /dev/nullvào giữa mỗi lệnh này và dấu chấm phẩy của chúng để ngăn nhiễu trên lỗi tiêu chuẩn, nhưng ngoài việc xấu, các thông báo lỗi là vô hại cho mục đích đếm các dòng.
pottaomme

8

wcchấp nhận đường dẫn tệp làm đầu vào, bạn cũng có thể sử dụng thay thế quy trình:

wc -l <(cat wordlist.txt; ls ~/folder/*)

Điều này gần tương đương với:

echo wordlist.txt > temp
ls ~/folder/* >> temp
wc -l temp

Lưu ý rằng ls ~/folder/*cũng trả về nội dung của các thư mục con nếu có (do mở rộng toàn cầu). Nếu bạn chỉ muốn liệt kê nội dung ~/folder, chỉ cần sử dụng ls ~/folder.


Đây wc -lchỉ là một ví dụ được tạo ra, tôi thực sự đang đưa nó vào một thứ phức tạp hơn mà không có tùy chọn này.
David Oneill

2
@DavidOneill Vâng, vì catchấp nhận một đối số tệp, bạn có thể sử dụng cat <(cat wordlist.txt; ls wordlist.txt) | wc -lvà thậm chí cat wordlist.txt <(ls wordlist.txt) | wc -l. Điều này tất nhiên là rất xấu, nhưng nó cho thấy khả năng vô tận với các công cụ dòng lệnh.
Lekensteyn

1
@DavidOneill Đúng, tôi đã sửa nó ngay, cảm ơn.
Lekensteyn

1
Bạn muốn ls ~/folder/sao cho nếu ~/foldermột liên kết tượng trưng lsliệt kê nội dung của mục tiêu thay vì chính liên kết đó. Nhân tiện, tất cả các lslệnh phải được theo sau -1để một tệp duy nhất trên mỗi dòng được in và wc -llà một cách đếm tập tin hợp lệ.
pottaomme

@pablomme Bạn đúng về điều liên kết tượng trưng, ​​nhưng -1được ngụ ý vì đầu ra không phải là một thiết bị đầu cuối mà là một đường ống.
Lekensteyn

2

Tôi đã tự hỏi mình câu hỏi tương tự, và cuối cùng đã viết một kịch bản ngắn.

magicalUnionThing(Tôi gọi nó append):

#!/bin/sh
cat /dev/stdin
$*

Làm cho tập lệnh đó được thực thi

chmod +x ./magicalUnionThing

Bây giờ bạn làm

cat wordlist.txt |./magicalUnionThing ls ~/folder/* | wc -l

Những gì nó làm:

  • Gửi đầu vào tiêu chuẩn đến đầu ra tiêu chuẩn
  • Thực hiện lập luận. $*trả về tất cả các đối số dưới dạng một chuỗi. Theo mặc định, đầu ra của lệnh đó đi đến đầu ra tiêu chuẩn kịch bản.

Vì vậy, thiết bị xuất chuẩn của MagicalUnionThing sẽ là stdin + stdout của lệnh được truyền dưới dạng đối số.

Tất nhiên có những cách đơn giản hơn, theo các câu trả lời khác.
Có lẽ sự thay thế này có thể hữu ích trong một số trường hợp.

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.