Câu trả lời ngắn: xem BashAQ # 50: Tôi đang cố gắng đặt một lệnh vào một biến, nhưng các trường hợp phức tạp luôn thất bại! .
Câu trả lời dài: đó là do thứ tự bash phân tích dòng lệnh. Cụ thể, nó tìm kiếm những thứ như đường ống và chuyển hướng trước khi nó mở rộng các giá trị biến đổi, và không quay lại và tìm kiếm lại các đường ống, v.v. trong các giá trị mở rộng. Về cơ bản, các biến được thay thế khoảng một nửa trong quá trình phân tích cú pháp, do đó, giá trị chỉ được phân tách một nửa trước khi được thực thi.
Để giải quyết vấn đề này, bạn cần trả lời câu hỏi của @ slhck: tại sao lệnh được lưu trữ trong một biến ở vị trí đầu tiên? Vấn đề thực tế bạn đang cố gắng giải quyết là gì? Tùy thuộc vào mục tiêu thực tế, có một số giải pháp có thể:
Đừng lưu nó trong một biến, chỉ cần thực hiện trực tiếp. Lưu trữ các lệnh để sử dụng sau này là khó khăn và nếu bạn không thực sự cần, thì đừng.
Sử dụng một hàm thay vì một biến. Rốt cuộc, đó là những gì họ dành cho:
i() { cat -nT index.php |grep 'someregex'; }
i
Nhược điểm chính của điều này là bạn không thể tạo hàm một cách linh hoạt - bạn không thể bao gồm hoặc loại trừ mã khỏi hàm một cách có điều kiện (mặc dù chính hàm có thể có các phần tử có điều kiện được chọn khi nó được thực thi).
Sử dụng eval
. Đây nên được coi là phương sách cuối cùng, vì nó dễ dàng có hành vi bất ngờ. Về cơ bản, nó chạy lệnh thông qua một phân tích cú pháp phân tích đầy đủ khác, vì vậy tất cả các ống vv đều có ý nghĩa đầy đủ của chúng - nhưng điều đó cũng có nghĩa là các phần của lệnh bạn nghĩ chỉ là dữ liệu cũng sẽ được phân tích cú pháp và có thể được thực thi. Tên tệp có chứa siêu ký tự vỏ (ống, dấu chấm phẩy, trích dẫn / dấu nháy đơn, v.v.) có thể có tác dụng kỳ lạ và đôi khi nguy hiểm. Nếu bạn sử dụng eval
, ít nhất là trích dẫn hai chuỗi, nếu không, nội dung của chuỗi về cơ bản sẽ được phân tích cú pháp một lần rưỡi, với kết quả thậm chí kỳ lạ hơn.
i="cat -nT index.php |grep 'someregex'"
eval "$i"
EDIT: Một cách tiếp cận cửa hàng-a-lệnh-in-a-biến tiêu chuẩn khác là sử dụng một mảng thay vì một biến đơn giản. Điều này cho phép bạn lưu trữ một lệnh với các đối số phức tạp (ví dụ như chứa khoảng trắng) mà không gặp sự cố, nhưng sẽ không lưu trữ những thứ như đường ống và chuyển hướng. Vì vậy, cách tiếp cận mảng sẽ không hữu ích trong trường hợp cụ thể này.