Làm thế nào để tôi khác đầu ra của hai lệnh?


165

Tôi đã tưởng tượng cách đơn giản nhất để so sánh nội dung của hai thư mục tương tự sẽ giống như

diff `ls old` `ls new`

Nhưng tôi thấy tại sao điều này không hoạt động; diffđang được trao một danh sách dài các tệp trên dòng lệnh, thay vì hai luồng như tôi đã hy vọng. Làm thế nào để tôi chuyển hai đầu ra cho diff trực tiếp?


Câu trả lời:


246

Thay thế lệnh thay `…`thế đầu ra của lệnh vào dòng lệnh, vì vậy diffxem danh sách các tệp trong cả hai thư mục là đối số. Những gì bạn muốn là diffđể xem hai tên tệp trên dòng lệnh của nó và có nội dung của các tệp này là danh sách thư mục. Đó là những gì quá trình thay thế làm.

diff <(ls old) <(ls new)

Các đối số diffsẽ trông giống như /dev/fd/3/dev/fd/4: chúng là các mô tả tệp tương ứng với hai đường ống được tạo bởi bash. Khi diffmở các tệp này, nó sẽ được kết nối với phía đọc của mỗi ống. Phía ghi của mỗi ống được kết nối với lslệnh.


49
echo <(echo) <(echo)không bao giờ nghĩ rằng điều này có thể thú vị như vậy: D
Sức mạnh Bảo Bình

3
Thay thế quy trình không được hỗ trợ bởi tất cả các vỏ , nhưng chuyển hướng đường ống là một cách giải quyết gọn gàng .
Irfan434

1
Chỉ cần đề cập rằng phân tích ls không được khuyến nghị unix.stackexchange.com/questions/128985/why-not-parse-ls
Katu

@Katu Vấn đề với lslà nó mang tên tệp. Phân tích cú pháp đầu ra của nó rất dễ hỏng (nó không hoạt động với các tên tập tin kỳ quặc). Để so sánh hai danh sách thư mục, không sao miễn là đầu ra không rõ ràng. Với tên tệp tùy ý, điều này sẽ yêu cầu một tùy chọn như --quoting-style=escape.
Gilles

1
@will <(…)tạo đường ống. Có vẻ như meld không hoạt động với đường ống, vì vậy bạn không thể sử dụng <(…). Trong zsh, bạn có thể thay thế <(…)bằng =(…)và nó sẽ hoạt động vì =(…)đặt các đầu ra trung gian trong một tệp tạm thời. Trong bash tôi không nghĩ có bất kỳ cú pháp thuận tiện nào, bạn phải tự mình quản lý các tệp tạm thời.
Gilles

3

Đối với zsh, sử dụng =(command)tự động tạo một tệp tạm thời và thay thế =(command)bằng đường dẫn của chính tệp đó. Với Lệnh thay thế, $(command)được thay thế bằng đầu ra của lệnh.

Vì vậy, có ba lựa chọn:

  1. Lệnh thay thế: $(...)
  2. Quy trình thay thế: <(...)
  3. thay thế quy trình hương vị zsh: =(...)

Hợp đồng quy trình có hương vị zsh, # 3, rất hữu ích và có thể được sử dụng như vậy để so sánh đầu ra của hai lệnh bằng công cụ diff, ví dụ Beyond So sánh:

bcomp  =(ulimit -Sa | sort) =(ulimit -Ha | sort)

Đối với Beyond So sánh, lưu ý rằng bạn phải sử dụng bcompcho mục đích trên (thay vì bcompare) kể từ khi bcompkhởi chạy so sánh và chờ đợi nó hoàn thành. Nếu bạn sử dụng bcompare, nó sẽ khởi chạy so sánh và thoát ngay lập tức do các tệp tạm thời được tạo để lưu trữ đầu ra của các lệnh biến mất.

Đọc thêm tại đây: http://zsh.sourceforge.net/Intro/intro_7.html

Cũng lưu ý điều này:

Lưu ý rằng shell tạo một tệp tạm thời và xóa nó khi lệnh kết thúc.

và sau đây là sự khác biệt giữa hai loại Thay thế quy trình được zsh hỗ trợ (tức là # 2 và # 3):

Nếu bạn đọc trang man của zsh, bạn có thể nhận thấy rằng <(...) là một hình thức thay thế quy trình khác tương tự như = (...). Có một sự khác biệt quan trọng giữa hai. Trong trường hợp <(...), shell tạo ra một ống có tên (FIFO) thay vì một tệp. Điều này là tốt hơn, vì nó không lấp đầy hệ thống tập tin; nhưng nó không hoạt động trong mọi trường hợp. Trên thực tế, nếu chúng ta đã thay thế = (...) bằng <(...) trong các ví dụ ở trên, tất cả chúng sẽ ngừng hoạt động ngoại trừ fgrep -f <(...). Bạn không thể chỉnh sửa đường ống hoặc mở nó dưới dạng thư mục thư; fgrep, tuy nhiên, không có vấn đề với việc đọc danh sách các từ từ một đường ống. Bạn có thể tự hỏi tại sao thanh diff <(foo) không hoạt động, vì foo | công trình khác biệt; điều này là do diff tạo một tệp tạm thời nếu nó thông báo rằng một trong các đối số của nó là - và sau đó sao chép đầu vào tiêu chuẩn của nó vào tệp tạm thời.

Tham khảo: https://unix.stackexchange.com/questions/393349/difference-b between-subshells-and-process-substlation


2
$(...)không phải là quá trình thay thế, đó là sự thay thế lệnh . <(...)là quá trình thay thế. Đó là lý do tại sao đoạn trích dẫn không đề cập gì $(...)cả.
muru

2

Vỏ cá

Trong vỏ cá bạn phải ống vào psub . Dưới đây là một ví dụ về so sánh cấu hình heroku và dokku với Beyond So sánh :

bcompare (ssh me@myapp.pl dokku config myapp | sort | psub) (heroku config -a myapp | sort | psub)

1
Một công cụ khác về đồ họa meldlà mã nguồn mở và có sẵn trong kho Ubuntu và EPEL. meldmerge.org
phiphi

0

Tôi thường sử dụng kỹ thuật được mô tả trong câu trả lời được chấp nhận:

diff <(ls old) <(ls new)

nhưng tôi thấy tôi thường sử dụng nó với các lệnh phức tạp hơn nhiều so với ví dụ trên. Trong những trường hợp như vậy có thể gây khó chịu khi tạo lệnh diff. Tôi đã đưa ra một số giải pháp mà những người khác có thể thấy hữu ích.

Tôi thấy rằng 99% thời gian tôi thử các lệnh có liên quan trước khi chạy diff. Do đó, các lệnh tôi muốn tìm khác nhau có ngay trong lịch sử của tôi ... tại sao không sử dụng chúng?

Tôi sử dụng hàm bash Fix Command (fc) để thực thi hai lệnh cuối:

$ echo A
A
$ echo B
B
$ diff --color <( $(fc -ln -1 -1) ) <( $(fc -ln -2 -2 ) )
1c1
< B
---
> A

Các cờ fc là:

-n : Không có số. Nó triệt tiêu các số lệnh khi liệt kê.

-l : Liệt kê: Các lệnh được liệt kê trên đầu ra tiêu chuẩn.

các -1 -1tham khảo khi bắt đầu và kết thúc positing trong lịch sử, trong trường hợp này nó từ lệnh cuối cùng để các lệnh cuối cùng trong đó sản lượng chỉ lệnh cuối cùng.

Cuối cùng, chúng tôi gói nó vào $()để thực thi lệnh trong một lớp con.

Rõ ràng đây là một chút khó khăn để gõ để chúng ta có thể tạo bí danh:

alias dl='diff --color <( $(fc -ln -1 -1) ) <( $(fc -ln -2 -2 ) )'

Hoặc chúng ta có thể tạo một hàm:

dl() {
    if [[ -z "$1" ]]; then
        first="1"
    else
        first="$1"
    fi
    if [[ -z "$2" ]]; then
        last="2"
    else
        last="$2"
    fi
    # shellcheck disable=SC2091
    diff --color <( $(fc -ln "-$first" "-$first") ) <( $(fc -ln "-$last" "-$last") )
}

trong đó hỗ trợ chỉ định các dòng lịch sử sẽ sử dụng. Sau khi sử dụng cả hai tôi thấy bí danh là phiên bản tôi thích.

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.