Trường hợp mới char char trailing đi từ thay thế lệnh của tôi?


15

Các mã sau đây mô tả tốt nhất tình hình. Tại sao dòng cuối cùng không xuất ra char mới dòng cuối? Đầu ra của mỗi dòng được hiển thị trong bình luận. Tôi đang sử dụng GNU bash, phiên bản 4.1.5

     echo -n $'a\nb\n'                  | xxd -p  # 610a620a  
           x=$'a\nb\n'   ; echo -n "$x" | xxd -p  # 610a620a
     echo -ne "a\nb\n"                  | xxd -p  # 610a620a
x="$(echo -ne "a\nb\n")" ; echo -n "$x" | xxd -p  # 610a62

4
Cách giải quyết cho những lần hiếm hoi khi cần:tmp=$(somecommand; echo a); tmp=${tmp%a}
Gilles 'SO- ngừng trở nên xấu xa'


1
@Gilles: Re ví dụ của bạn, ở trên: tmp=$(somecommand; echo a)... Điều này chắc chắn đã dẫn điểm về nhà ... Cho đến khi tôi nhìn thấy ví dụ này, xu hướng của tôi vẫn sẽ được sử dụng echo -n a... nhưng, tất nhiên!, Không cần các -n, vì lệnh Thay sẽ loại bỏ các newline trailing giới thiệu trong mọi trường hợp! ... cảm ơn ...
Peter.O

Câu trả lời:


18

Hàm thay thế lệnh $()(và anh em họ của nó là backtick) đặc biệt loại bỏ các dòng mới. Đây là hành vi được ghi lại và bạn phải luôn luôn biết về nó khi sử dụng cấu trúc.

Các dòng mới bên trong thân văn bản không bị loại bỏ bởi toán tử thay thế, nhưng chúng cũng có thể bị xóa khi thực hiện phân tách từ trên vỏ, vì vậy làm thế nào điều đó phụ thuộc vào việc bạn có sử dụng dấu ngoặc kép hay không. Lưu ý sự khác biệt giữa hai cách sử dụng này:

$ echo -n "$(echo -n 'a\nb')"
a
b

$ !! | xxd -p
610a62

$ echo -n  $(echo -n 'a\nb')
a b

$ !! | xxd -p   
612062

Trong ví dụ thứ hai, đầu ra không được trích dẫn và dòng mới được hiểu là phân chia từ, làm cho nó hiển thị trong đầu ra dưới dạng khoảng trắng!


1
Cảm ơn Caleb .. Tôi đã biết về việc thay đổi khoảng trắng từ chia thành một khoảng trắng khi không được trích dẫn ... Đó là lý do tại sao tôi ngạc nhiên nhất khi thấy dòng mới của tôi biến mất ngay cả khi tôi đã trích dẫn nó ... Bây giờ tôi biết rằng đó là vì hành vi 'bình thường' của Thay thế chỉ huy bỏ một dòng mới ... Ôi, xin chào, và cảm ơn vì đường dẫn
Peter.O

6

Khi sử dụng thay thế lệnh, shell thực thi các lệnh trong một lớp con, trả về thiết bị xuất chuẩn của chúng. trong quá trình này, các ký tự IFS mất đi tầm quan trọng của chúng (nếu chúng không được trích dẫn), vì phần thưởng sẽ trả về các từ được chia đơn giản, do đó các ký tự dấu được loại bỏ. Ví dụ:

$ echo "$(echo -e '\n')" | wc
 1       0       1

$ echo -e '\n' | wc
2       0       2

và thực tế hơn, pwdsẽ hoạt động ngay cả khi tên thư mục của bạn có một dòng mới ở giữa, nhưng $(pwd)sẽ không.

Cách giải quyết thông thường là thêm một cái gì đó vào cuối lệnh của bạn và loại bỏ nó sau đó.


1
Cảm ơn Philomath ... nhân tiện, ví dụ đầu tiên của bạn là sai về mặt cú pháp ('wc' không chấp nhận một chuỗi như một đối số) .. Đối với các ví dụ của bạn có ý nghĩa, thì ví dụ đầu tiên có thể là echo "$(echo -e '\n')" | wc, kết quả đầu ra 1   0   1, so với2   0   2
Peter.O

@fred: Rất tiếc, chỉ là một lỗi đánh máy.
Philomath

1
"chuyển đổi thành không gian" không phải là lời giải thích phù hợp, chỉ có một số chia tách liên quan. Cụ thể, bạn có thể xóa không gian khỏi IFS và chúng sẽ không đóng vai trò là dấu phân cách. Hơn nữa, ví dụ của bạn rơi vào một trường hợp đặc biệt và có một sự khác biệt giữa $(pwd)"$(pwd)", xem câu trả lời của Caleb.
Stéphane Gimenez

Tái bút .. Đề xuất của bạn về cách giải quyết thông thường chỉ là những gì tôi cần để xóa cái này ..
Peter.O

Tái "chuyển đổi thành dấu cách", xem phần Chia tách từ
Peter.O
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.