bash - ganti ruang dengan baris baru

70

Bagaimana saya bisa mengganti spasi dengan baris baru pada input seperti:

/path/to/file /path/to/file2 /path/to/file3 /path/to/file4 /path/to/file5 dll ...

Untuk mendapatkan yang berikut ini:

/path/to/file
/path/to/file2
/path/to/file3
/path/to/file4
/path/to/file5

Catatan

Saya memposting pertanyaan ini untuk membantu pengguna lain, tidak mudah untuk menemukan jawaban yang berguna di UNIX SE sampai saya mulai mengetik pertanyaan ini. Setelah itu saya menemukan yang berikut:

Pertanyaan terkait

Bagaimana saya bisa menemukan dan mengganti dengan baris baru?

laconbass
sumber
ls / path / ke / | xargs echo | sed 's / \ s \ + / \ n / g'
SD.

Jawaban:

125

Gunakan trperintah

echo "/path/to/file /path/to/file2 /path/to/file3 /path/to/file4 /path/to/file5"\
| tr " " "\n"

Ditemukan di http://www.unix.com/shell-programming-scripting/67831-replace-space-new-line.html

laconbass
sumber
1
Tr adalah pemikiran pertama saya juga, meskipun ada begitu banyak cara untuk melakukannya! Ini benar-benar tepat untuk apa tr!
Rob
5
+1, tetapi sebagai komentar: Itu tidak berfungsi jika nama file mengandung spasi sendiri
Bonsi Scott
20

Dalam hal ini saya akan menggunakan printf:

printf '%s\n' /path/to/file /path/to/file2 /path/to/file3 /path/to/file4 /path/to/file5

Jika ada spasi di dalam salah satu jalur, Anda dapat mengutip filepath untuk mencegahnya terpecah pada spasi:

printf '%s\n' /path/to/file '/path/to/file with spaces' /path/to/another/file

Untuk mengubah teks secara umum, tradalah taruhan terbaik Anda, seperti tercakup dalam jawaban yang ada.

Evilsoup
sumber
1
Catatan singkat dari masa depan: terima kasih telah memposting solusi ini, sudah sangat andal bagi saya, dibandingkan dengan menggunakan "echo".
Liesmith
5

Dengan asumsi Anda memiliki string dengan spasi sebagai pemisah:

newline_separated=${space_separated// /$'\n'}

Namun Anda mungkin mengajukan pertanyaan yang salah. (Tidak harus, misalnya ini mungkin muncul dalam makefile.) Daftar nama file yang dipisahkan spasi tidak benar-benar berfungsi: bagaimana jika salah satu nama file berisi spasi?

Jika suatu program menerima nama file sebagai argumen, jangan bergabung dengan spasi. Gunakan "$@"untuk mengaksesnya satu per satu. Meskipun echo "$@"mencetak argumen dengan spasi di antaranya, itu karena echo: ia mencetak argumennya dengan spasi sebagai pemisah. somecommand "$@"meneruskan nama file sebagai argumen terpisah ke perintah. Jika Anda ingin mencetak argumen pada baris yang berbeda, Anda dapat menggunakan

printf '%s\n' "$@"

Jika Anda memiliki nama file yang dipisahkan oleh ruang dan Anda ingin meletakkannya dalam array untuk mengatasinya, Anda dapat menggunakan ekspansi variabel yang tidak dikutip untuk membagi nilai pada karakter IFS(Anda harus menonaktifkan ekspansi wildcard dengan set -f, jika tidak, pola akan diperluas nilainya):

space_separated_list='/path/to/file1 /path/to/file2 /path/to/file3'
IFS=' '; set -f
eval "array=(\$space_separated_list)"
for x in "${array[@]}"; do 

Anda bisa merangkum ini dalam fungsi yang mengembalikan -fpengaturan dan nilai IFSketika selesai:

split_list () {
  local IFS=' ' flags='+f'
  if [[ $- = *f* ]]; then flags=; fi
  set -f
  eval "$1=($2)"
  set $flags
}
split_list array '/path/to/file1 /path/to/file2 /path/to/file3'
for x in "${array[@]}"; do 
Gilles 'SANGAT berhenti menjadi jahat'
sumber
Mengubah jawaban yang benar untuk yang ini. Saya pikir lebih tepat untuk meneliti bagaimana saya sampai pada daftar yang dipisahkan oleh ruang, dan mengambil informasi itu dengan cara lain. Akan keren untuk pelajar seperti saya jika Anda berkomentar sedikit snipnet Anda, memberi tahu kami apa hal-hal seperti var IFS lokal atau kondisi $ - = f lakukan. Hal-hal semacam itu yang seseorang yang menggunakan bash beberapa kali tidak tahu.
laconbass
@ laconbass Saya telah menambahkan penjelasan singkat. Cari set -fdan IFSdi manual bash jika Anda ingin semua detailnya. Lihat juga unix.stackexchange.com/questions/16192/...
Gilles 'SO- stop being evil'
@Guilles Penjelasan singkat itu sudah cukup bagi saya, dan saya pikir itu akan menjadi untuk banyak orang lain. Ty untuk waktu Anda
laconbass
pengaturan IFSlokal tidak berlaku
Eliran Malka
@ EliranMalka Saya tidak tahu apa yang Anda maksudkan dengan ini. Jika skrip tidak berlaku seperti yang Anda pikirkan, Anda dapat mengajukan pertanyaan di sini.
Gilles 'SO- berhenti menjadi jahat'
4

Bersikap pragmatis, gunakan sed !!

sed 's/\s\+/\n/g' file

Kata di atas mengatakan untuk mengganti satu atau lebih karakter spasi putih (\ s +) dengan baris baru (\ n)

Ini kurang lebih:

'substitute /one space or more/ for /newline/ globally'
MGP
sumber
1
ganti perubahan dengan pengganti, itulah arti sebenarnya dari singkatan!
Rob
@Rob terima kasih, ingat Anda dapat mengedit jawaban orang lain.
MGP
1
Jika Anda memiliki beberapa spasi di antara teks maka Anda akan mendapatkan baris kosong. Anda perlu menambahkan '+' setelah \ untuk menunjukkan bahwa Anda ingin mencocokkan setidaknya satu spasi seperti yang seharusnya tepat satu ruang. yaitu. sed 's / \ s + / \ n / g'
DarkHeart
4

Sebagai alternatif trdari @laconbass, Anda juga dapat menggunakan xargsdalam hal ini:

echo "/path/to/file /path/to/file2 /path/to/file3 /path/to/file4  /path/to/file5"\
| xargs -n1

Keuntungannya adalah ia bekerja bahkan dengan banyak spasi putih, yang trtidak.

FranMowinckel
sumber
0

Inilah cara saya melakukannya:

echo "/path/to/file /path/to/file2 /path/to/file3 /path/to/file4 /path/to/file5" | sed 's/ /\
'/g

Perhatikan penggunaan tombol Enter setelah backslash dalam sedperintah.

unxnut
sumber
prons dan kontra apa yang telah sedberakhir tr?
laconbass
Tingkat kenyamanan Anda :-) Saya pikir Anda dapat melakukan lebih banyak sedkarena merupakan editor daripada hanya menerjemahkan karakter.
unxnut
4
seddapat melakukan lebih banyak lagi, tetapi benar-benar berlebihan untuk ini. tradalah alat yang tepat untuk pekerjaan INI, tetapi pengetahuan seddan regex tentu akan berguna nanti!
Rob
0

Pendekatan lain, dengan asumsi baris dalam variabel yang disebut line:

for path in $line;do echo $path;done

Ini memanfaatkan fakta bahwa Bash membagi argumennya pada spasi putih secara default dan echomenambahkan baris baru ke inputnya secara default.

Joseph R.
sumber
Saya mencoba ini di sistem ubuntu saya sebelum saya memposting pertanyaan ini dan tidak bisa berfungsi.
laconbass
0
echo word1 word2 ... | sed -e 'y/ /\n/;P;D'

adalah metode lain untuk mengubah kata-kata yang dipisahkan satu spasi menjadi baris yang dipisahkan.


sumber
-1

Skrip berikut mudah dimengerti dan mudah digunakan.

cat filename | tr ' ' '\n' | tee filename
sanjeev kanabargi
sumber
2
Inti dari jawaban Anda ( tr) sama dengan jawaban yang diterima. Selain itu jawaban Anda memiliki masalah berikut: a) perintah tidak diindentasi dengan 4 spasi (-> tata letak markdown) b) Penggunaan Anda cattidak berguna (Anda dapat menggantinya dengan < filename tr ' ' '\n'). c) Nama file keluaran Anda sama dengan nama file input. Dengan itu Anda membuat perlombaan data.
maxschlepzig
1
selain dari analisis maxschlepzig yang benar, ini bukan skrip, tetapi sekelompok perintah yang terhubung yang memiliki nama yang di-hardcod (karena skrip diharapkan memiliki header yang menentukan shell untuk digunakan dan menggunakan dua parameter untuk menentukan dalam dan output). Selain itu, 2 dari 3 orang di rumah saya tidak mudah memahaminya. Mungkin itu tidak representatif, tetapi perlu diingat bahwa sesuatu yang Anda sendiri pahami (atau dalam hal ini pikir Anda pahami) selalu tampak mudah.
Anthon