Cara menghapus baris baru dari string di Bash

110

Saya memiliki variabel berikut.

echo "|$COMMAND|"

yang kembali

|
REBOOT|

Bagaimana cara menghapus baris baru pertama itu?

Matt Leyland
sumber
7
Mengapa ini ditandai sebagai korban penipuan? Pertanyaan ini tentang melepas kereta kembali. Pertanyaan duplikat yang dituduhkan yang ditautkannya adalah tentang menghapus spasi, dan hanya secara tidak sengaja menyebutkan carriage return.
Michael Scheper
1
@MichaelScheper setuju dan membuka kembali.
fedorqui 'JADI berhenti melukai'
Istilahnya di sini aneh. Karakter penghentian baris Unix \n(hex 0x0A) disebut umpan kebohongan (LF); ini berbeda dari karakter carriage return (CR) \r(hex 0x0D) yang digunakan pada Windows dan di banyak protokol jaringan sebagai byte pertama dalam urutan akhir baris dua byte CR LF.
tripleee

Jawaban:

114

Dibawah , ada beberapa bashisme:

The trperintah dapat digantikan oleh // bashism :

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

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

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

Lihat Perluasan Parameter dan QUOTING di halaman manual bash:

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

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

Lebih lanjut...

Seperti yang diminta oleh @AlexJordan, ini akan menyembunyikan semua karakter yang ditentukan. Jadi bagaimana jika $COMMANDmemang mengandung spasi ...

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|

Segera:

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

catatan: memiliki extglobopsi untuk diaktifkan ( shopt -s extglob) untuk menggunakan *(...)sintaks.

F. Hauri
sumber
1
Ini adalah cara untuk menghapus linefeed dari variabel di BASH. Jawaban lain tidak perlu meminta proses TR ekstra. BTW, ini memiliki manfaat tambahan untuk menghilangkan spasi akhir!
ingyhere
1
Perhatikan bahwa itu juga menghapus spasi internal dari string juga ... COMMAND="RE BOOT"; echo "|${COMMAND//[$'\t\r\n ']}|"mengembalikan|REBOOT|
Alex Jordan
2
@AlexJordan Ya, ini adalah fitur yang diinginkan : Anda dapat menggunakan spasi setelahnya \nuntuk mencegah: COMMAND="RE BOOT"; echo "|${COMMAND//[$'\t\r\n']}|"akan kembali |RE BOOT|.
F. Hauri
2
Bagaimana pola tersebut bekerja ${COMMAND//[$'\t\r\n']}? Saya pikir ${COMMAND//[\t\r\n]}hanya akan berhasil, tetapi ternyata tidak. Untuk apa $simbol dan tanda kutip tunggal juga?
haridsv
1
Mengenai sintaks $ '', itulah kutipan ANSI C (disebutkan dalam jawaban wjordans).
chuckx
81
echo "|$COMMAND|"|tr '\n' ' '

akan mengganti baris baru (di POSIX / Unix ini bukan carriage return) dengan spasi.

Sejujurnya saya akan berpikir untuk beralih dari pesta ke sesuatu yang lebih waras. Atau menghindari pembuatan data yang salah format ini sejak awal.

Hmmm, sepertinya ini bisa menjadi lubang keamanan yang mengerikan juga, tergantung dari mana datanya berasal.

Robin Green
sumber
Tanggalnya berasal dari permintaan curl yang ada di server yang sama, Bagaimana saya akan memasukkannya ke dalam var baru? newvar = $ (echo "| $ COMMAND |" | tr '\ n' '')
Matt Leyland
2
Iya. Tapi tolong beritahu saya Anda tidak mengizinkan orang sembarangan untuk me-reboot server Anda dari jarak jauh tanpa kata sandi ...
Robin Green
31
Mengapa Anda tidak menggunakan tr -d '\n'untuk menjatuhkan bukannya diganti dengan spasi
F. Hauri
3
Tolong cambuk pipa yang tidak berguna! Gunakan tr '\n' ' ' <<< "|$COMMAND|"sebagai penggantiecho ... | ...
F. Hauri
12
@ F. Hauri: atau tr berguna:"|${COMMAND//$'\n'}|"
rici
75

Bersihkan variabel Anda dengan menghapus semua carriage return:

COMMAND=$(echo $COMMAND|tr -d '\n')
Maxime Chéramy
sumber
22
Bukankah itu strip feeds? Bukankah seharusnya demikian tr -d '\r'?
Izzy
3
Menggema variabel yang tidak diberi komentar akan menghapus semua karakter IFS (baris baru, spasi, tab secara default). Jadi jika Anda akan melakukan ini, Anda harus sadar bahwa semua karakter IFS dihapus, dan Anda tidak memerlukan ekstensi tr. Cukup COMMAND=$(echo $COMMAND)akan memberikan efek yang serupa. Artinya, mungkin, iblis bertelur karena memanggil proses baru, tetapi masih cukup singkat dan manis untuk mata manusia dan jika Anda memiliki satu atau dua detik tersisa dalam hidup Anda, Anda mungkin bersedia menerima pukulan :-).
Mike S
Saya telah memperbarui pertanyaan menjadi "linefeed", karena contohnya memang menunjukkan bahwa itu adalah linefeed, bukan carriage return. Jawaban ini masih benar, tetapi mungkin harus diperbarui menjadi "linefeed" daripada "carriage return"?
Benjamin W.
8

Menggunakan bash:

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

(Perhatikan bahwa karakter kontrol dalam pertanyaan ini adalah 'baris baru' ( \n), bukan carriage return ( \r); yang terakhir akan memiliki keluaran REBOOT|pada satu baris.)

Penjelasan

Menggunakan Perluasan Parameter Bash Shell${parameter/pattern/string} :

The pola diperluas untuk menghasilkan pola seperti dalam ekspansi nama file. Parameter diperluas dan kecocokan terpanjang pola terhadap nilainya diganti dengan string . [...] Jika string adalah nol, kecocokan pola dihapus dan pola / berikut dapat dihilangkan.

Juga menggunakan konstruksi $'' kutipan ANSI-C untuk menentukan baris baru sebagai $'\n'. Menggunakan baris baru secara langsung juga akan berhasil, meski kurang cantik:

echo "|${COMMAND/
}|"

Contoh lengkapnya

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

Atau, menggunakan baris baru:

#!/bin/bash
COMMAND="
REBOOT"
echo "|${COMMAND/
}|"
# Outputs |REBOOT|
wjordan.dll
sumber
6

Apa yang berhasil bagi saya adalah echo $testVar | tr "\n" " "

Di mana testVar berisi variabel / script-output saya

Prachi
sumber
4

Menambahkan jawaban untuk menunjukkan contoh pengupasan beberapa karakter termasuk \ r menggunakan tr dan menggunakan sed. Dan mengilustrasikan menggunakan hexdump.

Dalam kasus saya, saya telah menemukan bahwa perintah yang diakhiri dengan awk print dari item terakhir |awk '{print $2}'di baris termasuk carriage-return \ r serta tanda kutip.

Saya biasa sed 's/["\n\r]//g'menanggalkan carriage-return dan kutipan.

Saya juga bisa menggunakan tr -d '"\r\n'.

Menarik untuk diperhatikan sed -zdiperlukan jika seseorang ingin menghapus \ n karakter line-feed.

$ 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   |

Dan ini relevan: Apakah carriage return, linefeed, dan form feed?

  • CR == \ r == 0x0d
  • LF == \ n == 0x0a
astaga
sumber
3

Anda cukup menggunakan echo -n "|$COMMAND|".

Paulo
sumber
2

Jika Anda menggunakan bash dengan opsi extglob diaktifkan, Anda dapat menghapus hanya spasi kosong melalui:

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

Output ini:

|
RE BOOT|

Atau ganti %% dengan ## untuk hanya mengganti spasi di depan.

zeroimpl
sumber
1
Ini bekerja seperti pesona dengan beberapa keluaran aneh yang saya dapatkan dari perintah buruh pelabuhan. Terimakasih banyak!
develCuy