Cách thanh lịch để ngăn chặn thay thế lệnh từ bỏ dòng mới


7

Tôi đang tùy chỉnh zsh của mình PROMPTvà gọi một hàm có thể có hoặc không echocó chuỗi dựa trên trạng thái của biến môi trường:

function my_info {
    [[ -n "$ENV_VAR"]] && echo "Some useful information\n"
}

local my_info='$(my_info)'

PROMPT="${my_info}My awesome prompt $>"

Tôi muốn thông tin kết thúc trên một dòng mới, để nếu nó được đặt, nó sẽ xuất hiện trên dòng riêng của nó:

Some useful information
My awesome prompt $>

Tuy nhiên, nếu nó không được đặt, tôi muốn lời nhắc nằm trên một dòng duy nhất, tránh một dòng trống gây ra bởi một dòng mới vô điều kiện trong lời nhắc của tôi:

PROMPT="${my_info}  # <= Don't want that :)
My awesome prompt $>"

Hiện tại tôi làm việc xung quanh việc $(command substitution)xóa dòng mới của mình bằng cách thêm nó vào một ký tự không in, vì vậy dòng mới không bị kéo dài nữa:

[[ -n "$ENV_VAR"]] && echo "Some useful information\n\r"

Đây rõ ràng là một hack. Có cách nào sạch để trả về một chuỗi kết thúc trên một dòng mới không?

Chỉnh sửa: Tôi hiểu nguyên nhân gây ra sự mất mát của dòng mớilý do tại sao điều đó xảy ra , nhưng trong câu hỏi này tôi đặc biệt muốn biết cách ngăn chặn hành vi đó (và tôi không nghĩ cách giải quyết này áp dụng trong trường hợp của tôi, vì tôi tìm kiếm một dòng mới "có điều kiện").

Chỉnh sửa: Tôi đứng chính xác: cách giải quyết được tham chiếu thực sự có thể là một giải pháp khá hay (vì các chuỗi tiền tố trong so sánh là một mẫu phổ biến và hơi giống nhau), ngoại trừ tôi không thể làm cho nó hoạt động chính xác:

echo "Some useful information\n"x
  [...]
PROMPT="${my_info%x}My awesome prompt $>"

không tước dấu vết xcho tôi.

Chỉnh sửa: Điều chỉnh cách giải quyết được đề xuất cho sự kỳ lạ đó là mở rộng nhanh chóng, điều này hiệu quả với tôi:

function my_info {
    [[ -n "$ENV_VAR"]] && echo "Some useful information\n"x
}

local my_info='${$(my_info)%x}'

PROMPT="$my_info My awesome prompt $>"

Bạn là thẩm phán nếu đây là một giải pháp tốt hơn so với giải pháp ban đầu. Đó là một chút rõ ràng hơn, tôi nghĩ, nhưng nó cũng cảm thấy ít đọc hơn.



@ G-Man Thoạt nhìn có vẻ như câu hỏi superuser.com là một trận đấu, vì câu trả lời được chấp nhận nói rằng vấn đề không nằm ở sự thay thế lệnh mà là với lần tiếp theo echo. Đó không phải là trường hợp cho câu hỏi này.
dtk

Ôi! Bạn đúng; Tôi đọc nó quá nhanh.
G-Man nói 'Phục hồi Monica'

1
Làm thế nào câu hỏi này là một bản sao của unix.stackexchange.com/questions/17732/iêu ? Đó là câu hỏi tại sao hiệu ứng xảy ra và câu trả lời được chấp nhận giải thích nó. Như tôi đã nói trong lần chỉnh sửa đầu tiên của mình, tôi đã biết câu hỏi đó khi đăng bài này, vì vậy tôi biết tại sao nó lại xảy ra, nhưng nó không trả lời làm thế nào để ngăn chặn nó tốt nhất.
dtk

Câu trả lời:


4

Dòng mới cuối cùng được loại bỏ khỏi thay thế lệnh. Ngay cả zsh cũng không cung cấp tùy chọn để tránh điều này. Vì vậy, nếu bạn muốn duy trì các dòng mới cuối cùng, bạn cần sắp xếp cho chúng không phải là dòng mới cuối cùng.

Cách dễ nhất để làm điều này là in một ký tự phụ (không phải là dòng mới) sau dữ liệu mà bạn muốn lấy chính xác và xóa ký tự phụ cuối cùng đó khỏi kết quả của lệnh thay thế. Bạn có thể tùy ý đặt một dòng mới sau ký tự phụ đó, dù sao nó cũng sẽ bị xóa.

Trong zsh, bạn có thể kết hợp thay thế lệnh với thao tác chuỗi để loại bỏ ký tự phụ.

my_info='${$(my_info; echo .)%.}'
PROMPT="${my_info}My awesome prompt $>"

Trong kịch bản của bạn, hãy lưu ý rằng đó my_infokhông phải là đầu ra của lệnh, đó là đoạn mã shell để lấy đầu ra, sẽ được đánh giá khi dấu nhắc được mở rộng. PROMPT=${my_info%x}…không hoạt động vì điều đó cố gắng loại bỏ một kết quả cuối cùng xkhỏi giá trị của my_infobiến, nhưng nó kết thúc bằng ).

Trong các shell khác, điều này cần phải được thực hiện theo hai bước:

output=$(my_info; echo .)
output=${output%.}

Trong bash, bạn sẽ không thể gọi my_infotrực tiếp từ PS1; thay vào đó bạn cần gọi nó từ PROMPT_COMMAND.

PROMPT_COMMAND='my_info=$(my_info; echo .)'
PS1='${my_info%.}…'

Lưu ý rằng bạn cần setopt promptsubsttrong zsh để những người ${variables}được mở rộng trong lời nhắc.
Stéphane Chazelas

-1

Bạn có thể có chức năng của mình xuất ra các mã thoát được thoát, để khi nó được mở rộng, nó sẽ chuyển thành dòng mới.

$ function my_info {
>    [[ -n "$ENV_VAR"]] && echo 'Some useful information\\n'
>}
$ echo $(my_info)
Some useful information

$

1
Vâng, tôi đã thử điều đó (trong các biến thể khác nhau, bao gồm cả cơ chế cụ thể của zsh$'\n' ), nhưng nó không hoạt động, vì zsh không mở rộng kết quả \ntrong PROMPTchuỗi: /
dtk

Có phải đó là do các trích dẫn đơn trong bài tập biến của bạn không? local my_info='$(my_info)'? Hãy thử mà không có họ, hoặc chỉPROMPT="$(my_info) My awesome prompt $>"
gameufo

Không, zsh thậm chí không mở rộng PROMPT="Foo\nBar", trái ngược với $ ENV_VAR="Foo\nBar"; echo $ENV_VAR. Các trích dẫn đơn trong bài tập là cần thiết để biểu thức không được mở rộng khi tệp có nguồn gốc, vì "tham chiếu" biến chứa nên được giải quyết mỗi khi PROMPTbiến được đánh giá.
dtk
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.