Cách xóa một dòng mới khỏi một chuỗi trong Bash


110

Tôi có biến sau.

echo "|$COMMAND|"

cái nào trả về

|
REBOOT|

Làm cách nào để xóa dòng mới đầu tiên đó?


7
Tại sao điều này được đánh dấu là một bản dupe? Câu hỏi này là về việc xóa dấu xuống dòng. Câu hỏi bị cáo buộc trùng lặp mà nó liên kết đến là về việc xóa khoảng trắng và chỉ tình cờ đề cập đến các ký tự xuống dòng.
Michael Scheper

1
@MichaelScheper đã đồng ý và mở lại.
fedorqui 'VẬY đừng làm hại nữa'

Thuật ngữ ở đây là kỳ quặc. Ký tự kết thúc dòng Unix \n(hex 0x0A) được gọi là nguồn cấp dữ liệu nói dối (LF); nó khác với ký tự xuống dòng (CR) \r(hex 0x0D) được sử dụng trên Windows và trong nhiều giao thức mạng như là byte đầu tiên trong chuỗi hai byte kết thúc dòng CR LF.
tripleee

Câu trả lời:


114

Dưới , có một số bashisms:

Các trlệnh có thể được thay thế bằng // bashism :

COMMAND=$'\nREBOOT\r   \n'
echo "|${COMMAND}|"
|
   OOT
|

echo "|${COMMAND//[$'\t\r\n']}|"
|REBOOT   |

echo "|${COMMAND//[$'\t\r\n ']}|"
|REBOOT|

Xem Mở rộng thông sốBÁO GIÁ trong trang người đàn ông của bash:

man -Pless\ +/\/pattern bash
man -Pless\ +/\\\'string\\\' bash

man -Pless\ +/^\\\ *Parameter\\\ Exp bash
man -Pless\ +/^\\\ *QUOTING bash

Thêm nữa...

Theo yêu cầu của @AlexJordan, điều này sẽ chặn tất cả các ký tự được chỉ định. Vì vậy, điều gì xảy ra nếu $COMMANDcó chứa khoảng trắng ...

COMMAND=$'         \n        RE BOOT      \r           \n'
echo "|$COMMAND|"
|
           BOOT      
|

CLEANED=${COMMAND//[$'\t\r\n']}
echo "|$CLEANED|"
|                 RE BOOT                 |

shopt -q extglob || { echo "Set shell option 'extglob' on.";shopt -s extglob;}

CLEANED=${CLEANED%%*( )}
echo "|$CLEANED|"
|                 RE BOOT|

CLEANED=${CLEANED##*( )}
echo "|$CLEANED|"
|RE BOOT|

Ngắn gọn:

COMMAND=$'         \n        RE BOOT      \r           \n'
CLEANED=${COMMAND//[$'\t\r\n']} && CLEANED=${CLEANED%%*( )}
echo "|${CLEANED##*( )}|"
|RE BOOT|

Ghi chú: extglobtùy chọn được bật ( shopt -s extglob) để sử dụng *(...)cú pháp.


1
Đây là cách để tách nguồn cấp dữ liệu khỏi một biến trong BASH. Các câu trả lời khác không cần thiết phải gọi thêm một quá trình TR. BTW, nó có thêm lợi ích là xóa dấu cách kết thúc!
ingyhere

1
Lưu ý rằng nó cũng loại bỏ nội bộ không gian từ một chuỗi cũng ... COMMAND="RE BOOT"; echo "|${COMMAND//[$'\t\r\n ']}|"lợi nhuận|REBOOT|
Alex Jordan

2
@AlexJordan Có, đó là một tính năng mong muốn : Bạn có thể đánh dấu khoảng trắng sau \nđể ngăn điều này: COMMAND="RE BOOT"; echo "|${COMMAND//[$'\t\r\n']}|"sẽ quay trở lại |RE BOOT|.
F. Hauri

2
Làm thế nào là mô hình hoạt động trong ${COMMAND//[$'\t\r\n']}? Tôi nghĩ ${COMMAND//[\t\r\n]}đơn giản sẽ hoạt động, nhưng nó không. Là gì $biểu tượng cho và dấu nháy đơn quá?
haridsv

1
Về cú pháp $ '', đó là trích dẫn ANSI C (được đề cập trong câu trả lời wjordans).
chuckx

81
echo "|$COMMAND|"|tr '\n' ' '

sẽ thay thế dòng mới (trong POSIX / Unix, nó không phải là ký tự xuống dòng) bằng một khoảng trắng.

Thành thật mà nói, tôi sẽ nghĩ về việc chuyển từ bash sang một thứ gì đó lành mạnh hơn. Hoặc tránh tạo ra dữ liệu không đúng định dạng này ngay từ đầu.

Hmmm, đây có vẻ như là một lỗ hổng bảo mật khủng khiếp, tùy thuộc vào nguồn dữ liệu đến từ đâu.


Ngày đến từ một yêu cầu curl trên cùng một máy chủ, Làm cách nào để đưa nó vào một var mới? newvar = $ (echo "| $ COMMAND |" | tr '\ n' '')
Matt Leyland

2
Đúng. Nhưng hãy nói với tôi rằng bạn không cho phép những người tùy tiện khởi động lại máy chủ của bạn từ xa mà không cần mật khẩu ...
Robin Green

31
Tại sao bạn không sử dụng tr -d '\n'cho thả thay vì thay thế bởi một không gian
F. Hauri

3
Xin vui lòng đánh ống vô dụng! Sử dụng tr '\n' ' ' <<< "|$COMMAND|"thay vìecho ... | ...
F. Hauri

12
@ F.Hauri: hoặc tr's vô dụng:"|${COMMAND//$'\n'}|"
rici

75

Làm sạch biến của bạn bằng cách loại bỏ tất cả các dấu xuống dòng:

COMMAND=$(echo $COMMAND|tr -d '\n')

22
Dải đó không có nguồn cấp dữ liệu? Có nên tr -d '\r'thay thế không?
Izzy

3
Việc tạo ra một biến không chú thích sẽ xóa tất cả các ký tự IFS (dòng mới, khoảng trắng, tab theo mặc định). Vì vậy, nếu bạn định làm điều này, bạn nên biết rằng tất cả các ký tự IFS đều bị loại bỏ và bạn không cần tr. Đơn giản là COMMAND=$(echo $COMMAND)sẽ cho một hiệu ứng tương tự. Có lẽ là ác quỷ sinh ra khi nó gọi một quy trình mới, nhưng nó vẫn khá ngắn và ngọt ngào đối với mắt người và nếu bạn có một hoặc hai giây để rảnh rỗi trong cuộc sống của mình, bạn có thể sẵn sàng nhận đòn :-).
Mike S

Tôi đã cập nhật câu hỏi thành "linefeed", vì ví dụ của nó đã cho thấy rằng đó là linefeed, không phải là ký tự xuống dòng. Câu trả lời này vẫn đúng, nhưng có lẽ nên được cập nhật thành "linefeed" thay vì "xuống dòng"?
Benjamin W.

8

Sử dụng bash:

echo "|${COMMAND/$'\n'}|"

(Lưu ý rằng ký tự điều khiển trong câu hỏi này là 'dòng mới' ( \n), không phải là ký tự xuống dòng ( \r); ký tự sau sẽ có đầu ra REBOOT|trên một dòng.)

Giải trình

Sử dụng Mở rộng Tham số Bash Shell${parameter/pattern/string} :

Các mô hình được mở rộng để tạo ra một mô hình giống như trong việc mở rộng tên tập tin. Tham số được mở rộng và kết quả khớp dài nhất của mẫu so với giá trị của nó được thay thế bằng chuỗi . [...] Nếu chuỗi là null, các trận đấu của mô hình được xóa và / sau mô hình có thể được bỏ qua.

Cũng sử dụng cấu trúc $'' trích dẫn ANSI-C để chỉ định một dòng mới là $'\n'. Sử dụng một dòng mới trực tiếp cũng sẽ hoạt động, mặc dù ít đẹp hơn:

echo "|${COMMAND/
}|"

Đầy đủ ví dụ

#!/bin/bash
COMMAND="$'\n'REBOOT"
echo "|${COMMAND/$'\n'}|"
# Outputs |REBOOT|

Hoặc, sử dụng dòng mới:

#!/bin/bash
COMMAND="
REBOOT"
echo "|${COMMAND/
}|"
# Outputs |REBOOT|

6

Điều làm việc cho tôi là echo $testVar | tr "\n" " "

Nơi testVar chứa biến / script-output của tôi


4

Thêm câu trả lời để hiển thị ví dụ về việc loại bỏ nhiều ký tự bao gồm \ r sử dụng tr và sử dụng sed. Và minh họa bằng cách sử dụng hexdump.

Trong trường hợp của tôi, tôi nhận thấy rằng một lệnh kết thúc bằng awk print của mục cuối cùng |awk '{print $2}'trong dòng bao gồm một dấu xuống dòng \ r cũng như dấu ngoặc kép.

Tôi đã từng sed 's/["\n\r]//g'loại bỏ cả dấu xuống dòng và dấu ngoặc kép.

Tôi cũng có thể đã sử dụng tr -d '"\r\n'.

Điều thú vị cần lưu ý sed -zlà cần thiết nếu muốn xóa \ n ký tự nguồn cấp dữ liệu dòng.

$ COMMAND=$'\n"REBOOT"\r   \n'

$ echo "$COMMAND" |hexdump -C
00000000  0a 22 52 45 42 4f 4f 54  22 0d 20 20 20 0a 0a     |."REBOOT".   ..|

$ echo "$COMMAND" |tr -d '"\r\n' |hexdump -C
00000000  52 45 42 4f 4f 54 20 20  20                       |REBOOT   |

$ echo "$COMMAND" |sed 's/["\n\r]//g' |hexdump -C
00000000  0a 52 45 42 4f 4f 54 20  20 20 0a 0a              |.REBOOT   ..|

$ echo "$COMMAND" |sed -z 's/["\n\r]//g' |hexdump -C
00000000  52 45 42 4f 4f 54 20 20  20                       |REBOOT   |

Và điều này có liên quan: Ký tự xuống dòng, nguồn cấp dữ liệu dòng và nguồn cấp dữ liệu biểu mẫu là gì?

  • CR == \ r == 0x0d
  • LF == \ n == 0x0a

3

Bạn có thể đơn giản sử dụng echo -n "|$COMMAND|".


2

Nếu bạn đang sử dụng bash với tùy chọn extglob được bật, bạn chỉ có thể xóa khoảng trắng ở cuối thông qua:

shopt -s extglob
COMMAND=$'\nRE BOOT\r   \n'
echo "|${COMMAND%%*([$'\t\r\n '])}|"

Kết quả này là:

|
RE BOOT|

Hoặc thay %% bằng ## để chỉ thay thế khoảng trắng ở đầu.


1
Điều này hoạt động giống như một sự quyến rũ với một số đầu ra kỳ lạ mà tôi nhận được từ một lệnh docker. Cảm ơn rất nhiều!
develCuy
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.