it-swarm-vi.com

Làm cách nào tôi có thể gán đầu ra của lệnh cho biến Shell?

Tôi muốn gán kết quả của một biểu thức cho một biến và nối nó với một chuỗi, sau đó lặp lại nó. Đây là những gì tôi đã có:

#!/bin/bash
cd ~/Desktop;
thefile= ls -t -U | grep -m 1 "Screen Shot";
echo "Most recent screenshot is: "$thefile;

Nhưng kết quả đầu ra:

Screen Shot 2011-07-03 at 1.55.43 PM.png
Most recent screenshot is: 

Vì vậy, có vẻ như điều đó không được gán cho $thefile, và đang được in khi nó được thực thi.

82
Nathan G.

Bài tập Shell là một từ đơn, không có khoảng trắng sau dấu bằng. Vì vậy, những gì bạn đã viết sẽ gán một giá trị trống cho thefile; hơn nữa, vì phép gán được nhóm với một lệnh, nó làm cho thefile một biến môi trường và phép gán là cục bộ cho lệnh cụ thể đó, tức là chỉ có lệnh gọi ls mới thấy giá trị được gán.

Bạn muốn nắm bắt đầu ra của một lệnh, vì vậy bạn cần sử dụng thay thế lệnh :

thefile=$(ls -t -U | grep -m 1 "Screen Shot")

(Một số tài liệu hiển thị cú pháp thay thế thefile=`ls …`; Cú pháp backquote tương đương với cú pháp dấu ngoặc đơn ngoại trừ việc trích dẫn bên trong backquote đôi khi là lạ, vì vậy chỉ cần sử dụng $(…).)

Những nhận xét khác về kịch bản của bạn:

  • Kết hợp -t (Sắp xếp theo thời gian) với -U (Không sắp xếp) sẽ không có ý nghĩa; chỉ cần sử dụng -t.
  • Thay vì sử dụng grep để khớp với ảnh chụp màn hình, việc chuyển một ký tự đại diện sang ls sẽ rõ ràng hơn và sử dụng head để chụp tệp đầu tiên:

    thefile=$(ls -t *"Screen Shot"* | head -n 1)
    
  • Nói chung là một ý tưởng tồi để phân tích đầu ra của ls . Điều này có thể thất bại khá nặng nếu bạn có tên tệp với các ký tự không thể in được. Tuy nhiên, việc sắp xếp các tệp theo ngày rất khó khăn nếu không có ls, vì vậy đây là một giải pháp chấp nhận được nếu bạn biết bạn sẽ không có ký tự không thể in hoặc dấu gạch chéo ngược trong tên tệp.

  • Luôn sử dụng dấu ngoặc kép xung quanh thay thế biến, tức là ở đây viết

    echo "Most recent screenshot is: $thefile"
    

    Nếu không có dấu ngoặc kép, giá trị của biến được xem xét lại, điều này sẽ gây rắc rối nếu nó chứa khoảng trắng hoặc các ký tự đặc biệt khác.

  • Bạn không cần dấu chấm phẩy ở cuối dòng. Chúng dư thừa nhưng vô hại.
  • Trong tập lệnh Shell, thường bao gồm set -e . Điều này báo cho Shell thoát nếu có bất kỳ lệnh nào bị lỗi (bằng cách trả về trạng thái khác không).

Nếu bạn có GNU find (cụ thể là nếu bạn đang chạy Linux hoặc Cygwin không nhúng), có một cách tiếp cận khác để tìm tệp gần đây nhất: có find liệt kê các tệp và ngày tháng của họ và sử dụng sorttail để trích xuất tệp trẻ nhất.

thefile=$(find -maxdepth 1 -type f -name "*Screen Shot*" -printf "%[email protected] %p" |
          sort -k 1n | tail -n 1)

Nếu bạn sẵn sàng viết tập lệnh này bằng zsh thay vì bash, có một cách dễ dàng hơn để bắt tệp mới nhất, bởi vì zsh có vòng loại toàn cầ cho phép ký tự đại diện không chỉ phù hợp với tên mà còn trên tệp metadata. Phần (om[1]) Sau mẫu là vòng loại toàn cầu; om sắp xếp các trận đấu theo độ tuổi tăng dần (tức là theo thời gian sửa đổi, lần đầu tiên mới nhất) và [1] chỉ trích xuất trận đấu đầu tiên. Toàn bộ trận đấu cần phải nằm trong ngoặc đơn vì về mặt kỹ thuật đó là một mảng, vì toàn cầu trả về một danh sách các tệp, ngay cả khi [1] Có nghĩa là trong trường hợp cụ thể này, danh sách chứa (nhiều nhất) một tệp.

#!/bin/zsh
set -e
cd ~/Desktop
thefile=(*"Screen Shot"*(om[1]))
echo "Most recent screenshot is: $thefile"

Nếu bạn muốn làm điều đó với multiline/nhiều lệnh/s thì bạn có thể làm điều này:

output=$( bash <<EOF
#multiline/multiple command/s
EOF
)

Hoặc là:

output=$(
#multiline/multiple command/s
)

Thí dụ:

#!/bin/bash
output="$( bash <<EOF
echo first
echo second
echo third
EOF
)"
echo "$output"

Đầu ra:

first
second
third
4
Jahid