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


76

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 chỉ định $thefilevà đang được in khi nó được thực thi.


Câu trả lời:


108

Một gán vỏ là một từ duy nhất, không có khoảng trắng sau dấu bằng. Vì vậy, những gì bạn đã viết 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ó tạo ra thefilemột biến môi trường và phép gán là cục bộ của lệnh cụ thể đó, tức là chỉ có lệnh gọi để lsxem 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 cho thấy một 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 lsvà sử dụng headđể chụp tệp đầu tiên sẽ rõ ràng hơ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ủals . Điều này có thể thất bại khá nặng nếu bạn có tên tệp 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 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 luôn sử dụng dấu ngoặc kép xung quanh các thay thế khác nhau , 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 một kịch bản shell, thường bao gồm một ý tưởng tốt set -e. Điều này báo cho shell thoát ra nếu 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 được nhúng), có một cách tiếp cận khác để tìm tệp gần đây nhất: findliệt kê các tệp và ngày tháng của chúng, và sử dụng sorttailtrích xuất tệp trẻ nhất.

thefile=$(find -maxdepth 1 -type f -name "*Screen Shot*" -printf "%T@ %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ầu cho phép khớp ký tự đại diện không chỉ trên tên mà còn trên siêu dữ liệu tệp. Phần (om[1])sau mẫu là vòng loại toàn cầu; omsắp xếp các trận đấu bằng cách tăng tuổi (tức là theo thời gian sửa đổi, mới nhất trước) và chỉ [1]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]phương tiện cụ thể trong danh sách này 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"

7
Ồ Nhiều thông tin hơn tôi có thể hy vọng. Cảm ơn bạn nhiều lần cho câu trả lời của bạn; Tôi thực sự đánh giá cao tất cả những nỗ lực bạn bỏ ra! Bạn đã cho tôi thấy rằng tôi thực sự, thực sự có rất nhiều điều để học hỏi. Tôi sẽ mua một cuốn sách về bash: P.
Nathan G.

3
Đó là những gì tôi sẽ gọi câu trả lời dứt khoát ! :)
alex

4

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

Đây là một câu trả lời tốt đẹp. Có cách nào để tôi có thể chỉ định một biến là một phần của lệnh không? ví dụoutput=$(echo $someVariable)
Zach Smith
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.