Sự khác biệt của việc sử dụng () và $ () để thực thi một loạt các lệnh


8

Tôi hiện đang cố gắng tạo một tập lệnh tạo các byte sẽ được chuyển thành đầu vào cho netcat.

Đây là ý tưởng của kịch bản:

(perl -e "print \"$BYTES\x00\";

cat file;

perl -e "print \"More bytes\"x16 . \"\r\n\"";) | netcat ip port

Tôi đã thử sử dụng cả hai bằng cách sử dụng lệnh con và thay thế lệnh (ví dụ: $ ()) để thực thi các lệnh. Tuy nhiên tôi không hiểu tại sao đầu ra của tập lệnh khi sử dụng thay thế lệnh là sai. Tôi nghi ngờ rằng sự thay thế lệnh không chính xác dẫn đầu ra của nó khi thực hiện nhiều lệnh. Ai đó có thể giải thích cho tôi tại sao điều này là như vậy?

BIÊN TẬP

Đây là biến thể sử dụng thay thế lệnh:

$(perl -e "print \"$BYTES\x00\";

cat file;

perl -e "print \"More bytes\"x16 . \"\r\n\"";) | netcat ip port

1
Thay thế lệnh được thay thế bởi đầu ra của nó. Đó là, đầu ra của lệnh đó ở dạng thay thế sẽ không được dẫn vào netcatvì nó sẽ chỉ là văn bản trống. Nếu bạn, ví dụ, được thêm vào echotrước khi thay thế lệnh bắt đầu, bạn có thể thấy rằng nó hoạt động.
HalosGhost

@HalosGhost Vì vậy, ý bạn là nói rằng các byte hex mà tôi đã cố tạo để trở thành văn bản ở dạng ascii? Tôi đã cố gắng thực hiện một hexdump của các đầu ra và điều khiến tôi bối rối là đầu ra từ sự thay thế lệnh chứa một tài liệu HTML và các byte hex mà tôi tạo ra dường như nằm bên trong nó.
MykelXIII

Không, ý tôi là, bạn có thể nghĩ bất kỳ lệnh nào bên trong lệnh thay thế là tương đương với việc gõ đầu ra của lệnh đó. Có nghĩa là, trong ví dụ thứ hai của bạn, kết quả chỉ là văn bản trần. Vì vậy, không có gì được dẫn vào netcatvì không có gì được chạy.
HalosGhost

@HalosGhost tôi thấy. Vì vậy, đầu ra của sự thay thế lệnh giống như gõ vào stdin gây ra không có gì để được đường ống? Tôi chưa quen với kịch bản và không hiểu điều này. Cảm ơn bạn rất nhiều. Nếu bạn chuyển bình luận của bạn vào phần câu trả lời tôi sẽ chấp nhận nó.
MykelXIII

Tôi đã cố gắng mở rộng câu trả lời của mình càng nhiều càng tốt để làm cho bức tranh rõ ràng và đơn giản nhất có thể.
HalosGhost

Câu trả lời:


16

Được rồi, hãy phá vỡ điều này. Một subshell thực thi nội dung của nó trong một chuỗi (nghĩa là nó nhóm chúng). Điều này thực sự có ý nghĩa trực quan như một lớp con được tạo ra đơn giản bằng cách bao quanh chuỗi lệnh với (). Nhưng, ngoài nội dung của lớp con được nhóm lại với nhau khi thực thi, bạn vẫn có thể sử dụng một lớp con như thể đó là một lệnh đơn. Đó là, một subshell vẫn có một stdin, stdoutstderrvì vậy bạn có thể dẫn mọi thứ đến và đi từ một subshell.

Mặt khác, thay thế lệnh không giống như chỉ đơn giản là xâu chuỗi các lệnh lại với nhau. Thay vào đó, thay thế lệnh có nghĩa là hoạt động giống như một truy cập biến nhưng với một lệnh gọi hàm. Các biến, không giống như các lệnh, không có các bộ mô tả tệp tiêu chuẩn, do đó bạn không thể dẫn bất cứ thứ gì đến hoặc từ một biến (nói chung), và điều tương tự cũng đúng với các thay thế lệnh.

Để cố gắng làm cho điều này rõ ràng hơn, những gì sau đây là một tập hợp các ví dụ có thể không rõ ràng (nhưng chính xác) và một tập hợp, những gì tôi nghĩ có thể là, ví dụ dễ hiểu hơn.

Hãy nói rằng date -ulệnh đưa ra như sau:

Thu Jul  2 13:42:27 UTC 2015

Nhưng, chúng tôi muốn thao tác đầu ra của lệnh này. Vì vậy, hãy đặt nó vào một cái gì đó như sed:

$ date -u | sed -e 's/ /    /g'
Thu    Jul        2    13:42:27    UTC    2015

Wow, thật là vui! Những điều sau đây hoàn toàn tương đương với ở trên (loại bỏ một số khác biệt về môi trường mà bạn có thể đọc trong các trang hướng dẫn về vỏ của bạn):

$ (date -u) | sed -e 's/ /    /g'
Thu    Jul        2    13:42:27    UTC    2015

Điều đó không có gì đáng ngạc nhiên vì tất cả những gì chúng tôi đã làm là nhóm date -u. Tuy nhiên, nếu chúng ta làm như sau, chúng ta sẽ nhận được một cái gì đó có vẻ hơi kỳ lạ lúc đầu:

$ $(date -u) | sed -e 's/ /    /g'
command not found: Thu

Điều này là do $(date -u)tương đương với việc gõ chính xác những gì date -uđầu ra. Vì vậy, ở trên là tương đương với sau đây:

$ Thu Jul  2 13:42:27 UTC 2015 | sed -e 's/ /    /g'

Tất nhiên, đó sẽ là lỗi vì Thukhông phải là lệnh (ít nhất không phải là lệnh tôi biết); và nó chắc chắn không dẫn đường gì cả stdout(vì vậy sedsẽ không bao giờ nhận được bất kỳ đầu vào nào).

Nhưng, vì chúng ta biết rằng các thay thế lệnh hoạt động giống như các biến, chúng ta có thể dễ dàng khắc phục vấn đề này bởi vì chúng ta biết cách chuyển giá trị của một biến sang một lệnh khác:

$ echo $(date -u) | sed -e 's/ /    /g'
Thu    Jul        2    13:42:27    UTC    2015

Nhưng, như với bất kỳ biến nào trong bash , có lẽ bạn nên trích dẫn thay thế lệnh bằng "".

Bây giờ, cho ví dụ có lẽ đơn giản hơn; xem xét những điều sau đây

$ pwd
/home/hypothetical
$ echo pwd
pwd
$ echo "$(pwd)"
/home/hypothetical
$ echo "$HOME"
/home/hypothetical
$ echo (pwd)
error: your shell will tell you something weird that roughly means “Whoa! you tried to have me echo something that isn't text!”
$ (pwd)
/home/hypothetical

Tôi không chắc làm thế nào để mô tả nó đơn giản hơn thế. Sự thay thế lệnh hoạt động giống như một truy cập biến trong đó lớp con vẫn hoạt động như một lệnh.


3

subshell

  • (command) sẽ thực thi lệnh trong subshell, điều này là hữu ích, nếu bạn có nhiều hơn một lệnh.

    • (ls) | wcsẽ dẫn lsđến wc, rõ ràng bạn có thể viếtls | wc
    • (ls ; date) | wcsẽ dẫn kết quả của cả hai lsdateđến wc. sử dụng ls ; date | wcsẽ dẫn đến chỉ dateđược dẫn đến wc.

thay thế

  • $(command)sẽ thực thi lệnh và thay thế bởi đầu ra. ví dụ

    echo $(date)

sẽ thay thế $(date)bằng Thu Jul 2 15:20:43 CEST 2015, sau đó

    echo Thu Jul  2 15:20:43 CEST 2015

đặt cùng nhau

bạn có thể kết hợp cả hai.

file=/hello/word
( printf "%s has %d bytes\n" ${file} $(wc -c < $file) ; date ) | netcat ... 
  • bạn có thể sử dụng $filehoặc${file}

Điều đó có nghĩa là tôi không thể sử dụng thay thế lệnh trên nhiều lệnh như sử dụng; để tách chúng?
MykelXIII

Chắc chắn bạn có thể. Nó sẽ không dẫn đến bất cứ điều gì stdoutvà thay vào đó sẽ thay thế nó bằng kết quả của biểu thức.
HalosGhost
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.