Không thể sử dụng! $ Trong tập lệnh?


11

Chỉ tự hỏi tại sao điều này không làm việc

#!/bin/bash 

ls /bin
ls !$

Tôi hy vọng sẽ chạy ls /binhai lần, nhưng lần thứ hai phát sinh lỗi vì !$không được giải thích

Tôi đã bỏ lỡ một cái gì đó, hoặc !$chỉ làm việc trong dòng lệnh?

Tôi không thể tìm thấy phần có liên quan trong man bash(trên mac)


9
Mặc dù có một giải pháp là đây thực sự là cách tốt nhất để đạt được điều này trong một kịch bản? lịch sử bị tắt theo mặc định vì một lý do khi bạn chạy không tương tác - một tập lệnh dài sẽ spam tệp .bash_history. Không nói rằng nó không đáng để hỏi điều này, nhưng chỉ là nếu bạn nghĩ đến việc sử dụng điều này trong một kịch bản, đây có thực sự là cách tốt nhất?
flungo

Câu trả lời:


26

Lịch sửmở rộng lịch sử bị tắt theo mặc định khi shell chạy không tương tác.

Bạn cần:

#!/bin/bash 

set -o history
set -o histexpand

ls /bin
ls !$

hoặc là:

SHELLOPTS=history:histexpand bash script.sh

nó sẽ ảnh hưởng đến tất cả các trường hợp bash script.shcó thể chạy.


9
cẩn thận với SHELLOPTS, nó sẽ ảnh hưởng đến việc bashchạy đó script.sh, nhưng tất cả các bashtrường hợp khác script.shcuối cùng có thể chạy (như các bashtập lệnh khác ...).
Stéphane Chazelas 5/2/2016

Và nó sẽ không ảnh hưởng đến bất kỳ trường hợp nào khác bash chạy tập lệnh của bạn.
Blacklight Shining

Tôi nghĩ câu trả lời này sẽ được cải thiện nếu bình luận của @ StéphaneChazelas được chỉnh sửa.
Oliphistic - phục hồi Monica

7

Điều lành mạnh cần làm là

ls /bin
ls $_

hoặc là

set ls /bin
$*
$*

hoặc là

c='ls /bin'
$c
$c

Hãy cẩn thận: đáng để nhớ rằng mỗi trong số chúng đi kèm với một số cạm bẫy. Giải pháp $ _ chỉ nắm bắt được đối số duy nhất cuối cùng: vì vậy ls foo barsẽ chỉ còn lại $ _ bar. Người sử dụng setsẽ ghi đè lên các đối số ( $1, $2, vv). Và tất cả những thứ này như được viết sẽ hoạt động, nhưng khi được khái quát hóa thành các lệnh phức tạp hơn (nơi thoát ra và vấn đề khoảng trắng), bạn có thể gặp một số khó khăn. Ví dụ: ls 'foo bar'(trong đó đối số tên đường dẫn đơn foo barchứa hai hoặc nhiều khoảng trắng hoặc bất kỳ ký tự khoảng trắng nào khác) sẽ không hoạt động chính xác trong một trong các ví dụ này. Thoát hiểm thích hợp (có thể kết hợp với một evallệnh), hoặc sử dụng "$@"thay vì $*, có thể cần thiết để khắc phục những trường hợp đó.


1
+1 cho câu trả lời là có thể mang theo và không lạm dụng một bashism nhằm mục đích sử dụng tương tác dễ dàng hơn. (Là một sang một bên, mong muốn bash để tương tác mở rộng dấu chấm than trong thiết lập mặc định là một cái gì đó tôi thấy phản trực giác như một người sử dụng của vỏ khác, và phản tác dụng vì nó luôn luôn vít tôi khi tôi đang cố gắng để làm một số lệnh shell phức tạp).
mtraceur 6/2/2016

Mặc dù như được viết tại thời điểm này, tôi đã do dự để cho nó +1 do các vấn đề mà người viết kịch bản shell mới bắt đầu có thể sẽ gặp phải khi cố gắng khái quát nó thành các lệnh phức tạp hơn. Tôi đề nghị một chỉnh sửa để ít nhất thêm một đoạn cảnh báo giải thích những cạm bẫy có thể có.
mtraceur 6/2/2016

@mtraceur: nó không di động, chỉ hoạt động trong bash, zsh, ksh (nếu hai lệnh không nằm trong cùng một dòng). Làm việc trong dấu gạch ngang, chỉ mksh khi tương tác
cuonglm 6/2/2016

@cuongim: Xin lỗi, có lẽ tôi đã quá bất cẩn. Các $_cách không phải là di động, bạn là đúng. Cách settiếp cận này hoạt động trong dấu gạch ngang không tương tác và với thủ thuật ${1+"$@"}(cộng với bí danh toàn cầu zsh) nên nói chung, mặc dù tôi mơ hồ nhớ rằng setcó một lịch sử không thể di động hoàn hảo với một số vỏ (cũ?). Cách tiếp cận xác định-a-biến-giữ-lệnh-và-sau đó-eval-it, đặc biệt là sử dụng lối thoát phù hợp và evallệnh thực tế , hoàn toàn có thể di chuyển theo như tôi biết.
mtraceur 6/2/2016
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.