Baris baru dalam pada Mac OS X

44

Saya menemukan bahwa \nitu tidak bekerja di bawah Mac OS X. Secara khusus, katakan saya ingin memecah kata-kata yang dipisahkan oleh satu spasi menjadi garis-garis:

# input
foo bar

Saya menggunakan,

echo "foo bar" | sed 's/ /\n/'

Tapi hasilnya bodoh, \ntidak luput!

foonbar

Setelah saya berkonsultasi ke google, saya menemukan solusinya :

echo 'foo bar' | sed -e 's/ /\'$'\n/g'

Setelah membaca artikel itu, saya masih tidak mengerti apa \'$'\n/g'artinya. Bisakah seseorang menjelaskannya kepada saya, atau jika ada cara lain untuk melakukannya? Terima kasih!

Ivan ZG Xiao
sumber
ini mungkin akan bekerja juga:echo "foo bar" | tr ' ' '\n'
glenn jackman
3
Terima kasih atas sarannya. Tetapi saat ini saya hanya menggunakan kasus di atas sebagai contoh, saya perlu tahu bagaimana cara melarikan diri \n.
Ivan ZG Xiao
Kemungkinan duplikat: stackoverflow.com/questions/21621722/…
hyiltiz

Jawaban:

27

Anda dapat brew install gnu-seddan mengganti panggilan seddengan gsed.

Jika Anda tidak ingin menambahkan "g" ke sed, Anda bisa brew install gnu-sed --with-default-namesdan cukup menelepon sed.

(Edit: bendera bir yang diperbarui, ujung topi ke Clément.)

Ahmed Fasih
sumber
Menggunakan perangkat lunak yang sama pada semua platform jauh lebih mudah (akhirnya bagi saya) daripada berurusan dengan setiap kekhususan versi Mac. Hati-hati, pilihannya sekarang --with-default-namesdan tidak --default-names . Namun, opsi ini tidak berfungsi pada instalasi saya, jadi saya harus memasukkan alias gsed=sedsaya ~/.profileuntuk membuatnya berfungsi.
Clément
4
Ini adalah solusi buruk. Itu tidak menjelaskan mengapa sedpada OS X berperilaku seperti itu dan membuat asumsi yang salah yang gnu-sedlebih benar. Jangan menjadi pecandu GNU dan tetap berpegang pada standar POSIX untuk menghindari masalah dalam jangka panjang.
octosquidopus
Begitulah cara Apple seharusnya membuat OS-nya bekerja secara default. Mengapa menggunakan nama program dan kemudian membuatnya bekerja secara berbeda? Saya buang waktu satu jam karena ini ...
rascio
@rascio - karena OS X mirip BSD dan Linux mirip Linux.
iAdjunct
@rascio Saya pikir Anda akan menemukan bahwa sed GNU adalah pendatang baru; BSD sed tanggal kembali ke 1979 (lihat en.wikipedia.org/wiki/Version_7_Unix ).
Duncan Bayne
24

Ini juga akan bekerja:

echo 'foo bar' | sed 's/ /\
/g'

echo 'foo bar' | sed $'s/ /\\\n/g'

lf=$'\n'; echo 'foo bar' | sed "s/ /\\$lf/g"

Sed OS X tidak menginterpretasikan \ndalam pola ganti, tetapi Anda dapat menggunakan umpan baris literal yang diawali oleh karakter kelanjutan garis. Shell menggantikan $'\n'dengan linefeed literal sebelum perintah sed dijalankan.

Lri
sumber
4
Mengapa sed $'s/ /\\\n/g'berhasil, tetapi tidak sed $'s/\\\n/ /g'?
Alec Jacobson
1
@ alec Anda tidak dapat menggunakan sedbahkan di linux / unix untuk menghapus baris baru karena diuraikan / dibagi di setiap baris baru. Jika Anda menjalankan ini di linux / unix, itu tidak akan melakukan apa pun:echo -e 'foo\nbar' | sed 's/\n//'
wisbucky
10

Solusi yang Anda temukan melewati string argumen tunggal ke sed -e.

Argumen itu akhirnya menjadi string dalam s/ / /gformat sed yang umum .

Tali itu dibuat dalam dua bagian, satu demi satu.

Bagian pertama dikutip dalam '...'bentuk.

Bagian kedua dikutip dalam $'...'bentuk.

Bagian 's/ /\'mendapatkan tanda kutip tunggal dilucuti, tetapi sebaliknya melewati sed seperti yang terlihat pada baris perintah. Artinya, backslash tidak dimakan oleh bash, itu diteruskan ke sed.

Bagian $'\n/g'mendapat tanda dolar dan tanda kutip tunggal dilepas, dan yang \ndikonversi menjadi karakter baris baru.

Secara keseluruhan, argumen menjadi

s / / \ newline/ g

[Itu tadi menyenangkan. Butuh waktu beberapa saat untuk membukanya. +1 untuk pertanyaan yang menarik.]

Spiff
sumber
7

Ungkapannya $'...'adalah bash-ism yang menghasilkan ...dengan urutan pelarian standar diperluas. Th \'sebelum itu hanya berarti garis miring terbalik diikuti oleh akhir bagian yang dikutip, string yang dihasilkan adalah s/ /\. (Ya, Anda dapat beralih mengutip di tengah-tengah string; itu tidak mengakhiri string.)

Standar POSIX sedhanya menerima \nsebagai bagian dari pola pencarian. OS X menggunakan FreeBSD sed, yang sepenuhnya sesuai dengan POSIX; GNU, seperti biasa, menambahkan hal-hal tambahan dan kemudian pengguna Linux semua berpikir bahwa itu semacam "standar" (mungkin saya akan lebih terkesan jika salah satu dari mereka memiliki proses standar).

geekosaurus
sumber
Sekarang saya mengerti $'...'bagian itu. Tapi ... apa itu s/ /\ ? Apa maksudmu switch quoting?
Ivan ZG Xiao
2
'...'adalah salah satu jenis kutipan shell; $'...'adalah yang lain. Ada juga "..."dan \xmengutip satu karakter. Anda dapat menggabungkan mereka dalam satu kata, yang sedang dilakukan di sana, beralih dari ''string normal ke $''string untuk menerjemahkan \n. Adapun sisanya, itu membangun sedperintah ( s/text/replacement/flags). Dalam hal ini perintah dimulai, termasuk garis miring terbalik di akhir untuk melindungi baris baru literal yang $'\n/g'ditambahkan. Hasilnya adalah untuk mengganti semua /gspasi ( bendera) dengan baris baru.
geekosaur
1

Ada yang sangat mudah untuk melihat secara visual apa yang terjadi. Cukup gema string!

echo 's/$/\'$'\n/g'

hasil dalam

s/$/\
/g

yang setara dengan s/$/\newline/g

Jika Anda tidak memiliki ekstra \sebelum newline, shell akan menafsirkan newlinesebagai akhir dari perintah sebelum waktunya.

Wisbucky
sumber