Bagaimana cara menggabungkan beberapa baris nama file menjadi satu dengan pembatas khusus?

441

Saya ingin menggabungkan hasil ls -1menjadi satu baris dan membatasi dengan apa pun yang saya inginkan.

Apakah ada perintah Linux standar yang dapat saya gunakan untuk mencapai ini?

JavaRocky
sumber

Jawaban:

689

Mirip dengan opsi pertama tetapi menghilangkan pembatas trailing

ls -1 | paste -sd "," -
Artem
sumber
29
Seperti catatan, versi tempel yang saya coba membutuhkan argumen "-" di bagian akhir untuk mengatakannya agar dibaca dari STDIN. mis. ls -1 | paste -s -d ":" - Tidak yakin apakah itu universal dengan semua versi tempel
Andy White
4
ini lebih baik karena memungkinkan pembatas kosong :)
Yura Purbeev
2
Catatan pastemendapat -(input standar) sebagai default, setidaknya di my paste (GNU coreutils) 8.22.
fedorqui 'SO berhenti merugikan'
1
Saya baru saja memutarnya, ini dan sekarang memiliki suara yang sama dengan jawaban yang dipilih. INI ADALAH JAWABANNYA. no trailing delimeter
thebugfinder
1
Pembatas kosong dapat ditentukan menggunakan "\0", jadi paste -sd "\0" -berfungsi untuk saya!
Taman Brad,
378

EDIT : Cukup " ls -m " Jika Anda ingin pembatas menjadi koma

Ah, kekuatan dan kesederhanaan!

ls -1 | tr '\n' ','

Ubah koma " , " menjadi apa pun yang Anda inginkan. Perhatikan bahwa ini termasuk "trailing koma"

zaf
sumber
46
+1, tetapi versi yang lebih rumit harus menangani terakhir \ n secara berbeda
mouviciel
5
Jika nama file berisi \ndi dalamnya, ini akan menggantikannya juga.
codaddict
3
@ShreevatsaR: maksudnya tidak menambahkan trailing "," Saya percaya. seperti ituls -1 | tr "\\n" "," | sed 's/\(.*\),/\1/'
Chris
7
@ Chris: Anda sedbisa menjadi sedikit lebih efisien dengan karakter penanda akhir:ls -1 | tr "\\n" "," | sed 's/,$//'; echo ''
pieman72
2
Menggunakan sedafter trtampaknya hanya untuk menghapus simbol terakhir tampaknya tidak masuk akal. Saya pergi denganls -1 | tr '\n' ',' | head -c -1
reddot
29

Ini menggantikan koma terakhir dengan baris baru:

ls -1 | tr '\n' ',' | sed 's/,$/\n/'

ls -m termasuk baris baru pada karakter lebar layar (misalnya ke-80).

Sebagian besar Bash (hanya lseksternal):

saveIFS=$IFS; IFS=$'\n'
files=($(ls -1))
IFS=,
list=${files[*]}
IFS=$saveIFS

Menggunakan readarray(alias mapfile) di Bash 4:

readarray -t files < <(ls -1)
saveIFS=$IFS
IFS=,
list=${files[*]}
IFS=$saveIFS

Terima kasih kepada gniourf_gniourf untuk sarannya.

Dijeda sampai pemberitahuan lebih lanjut.
sumber
Ini tidak akan menangani file dengan spasi putih di namanya. Coba yang ini: dir = / tmp / testdir; rm -rf $ dir && mkdir $ dir && cd / $ dir && sentuh "ini adalah file" this_is_another_file && ls -1 && file = ($ (ls -1)) && list = $ {file [@] /% / ,} && list = $ {list% *,} && echo $ list
dimir
1
@dimir: Banyak jawaban untuk pertanyaan ini menderita masalah ini. Saya telah mengedit jawaban saya untuk memungkinkan nama file dengan tab atau spasi, tetapi bukan baris baru.
Dijeda sampai pemberitahuan lebih lanjut.
Versi bash Anda juga menderita ekspansi pathname. Untuk membangun sebuah array dari garis, silakan mempertimbangkan menggunakan mapfile(Bash ≥4) sebagai: mapfile -t files < <(ls -1). Tidak perlu mengutak-atik IFS. Dan juga lebih pendek.
gniourf_gniourf
Dan ketika Anda memiliki array Anda, Anda dapat menggunakan IFSuntuk bergabung dengan bidang: saveIFS=$IFS; IFS=,; list=${files[*]}; IFS=$saveIFS. Atau gunakan metode lain jika Anda ingin pemisah dengan lebih dari satu karakter.
gniourf_gniourf
1
@ gniourf_gniourf: Saya telah memasukkan saran Anda dalam jawaban saya. Terima kasih.
Dijeda sampai pemberitahuan lebih lanjut.
24

Saya pikir ini luar biasa

ls -1 | awk 'ORS=","'

ORS adalah "pemisah rekaman keluaran" jadi sekarang baris Anda akan digabungkan dengan koma.

majkinetor
sumber
6
Ini tidak mengecualikan pembatas trailing.
Derek Mahar
6
Ini terutama luar biasa karena menangani pemisah rekaman multi-karakter (mis. " OR ")
Mat Schaffer
15

Kombinasi pengaturan IFSdan penggunaan "$*"dapat melakukan apa yang Anda inginkan. Saya menggunakan subkulit jadi saya tidak mengganggu $ IFS shell ini

(set -- *; IFS=,; echo "$*")

Untuk menangkap output,

output=$(set -- *; IFS=,; echo "$*")
glenn jackman
sumber
2
Apakah Anda memiliki informasi lebih lanjut tentang cara setkerjanya? Terlihat seperti voodoo bagiku. dangkal melihat melalui man settidak memberi saya banyak informasi baik.
Ehtesh Choudhury
3
Jika Anda memberikan setbanyak argumen tetapi tidak ada opsi, ia menetapkan parameter posisi ($ 1, $ 2, ...). --ada untuk melindungi setjika argumen pertama (atau nama file dalam kasus ini) terjadi mulai dengan tanda hubung. Lihat deskripsi --opsi di help set. Saya menemukan parameter posisi cara mudah untuk menangani daftar hal. Saya juga bisa menerapkan ini dengan sebuah array:output=$( files=(*); IFS=,; echo "${files[*]}" )
glenn jackman
Ini bagus karena tidak memerlukan mengeksekusi program tambahan dan bekerja dengan nama file yang berisi spasi atau bahkan baris baru.
Eric
1
@ EhteshChoudhury Seperti yang type setakan memberitahu Anda set is a shell builtin,. Jadi, man settidak akan membantu, tetapi help setakan dilakukan. Jawab: "- Tetapkan argumen yang tersisa ke parameter posisi."
Stéphane Gourichon
Setelah a set -- *. Menunda perluasan *satu tingkat Anda mungkin mendapatkan output yang benar tanpa perlu sub shell: IFS=',' eval echo '"$*"'. Tentu saja itu akan mengubah parameter posisi.
Isaac
13

Parsing lssecara umum tidak disarankan , jadi cara alternatif yang lebih baik adalah menggunakan find, misalnya:

find . -type f -print0 | tr '\0' ','

Atau dengan menggunakan finddan paste:

find . -type f | paste -d, -s

Untuk penggabungan umum beberapa baris (tidak terkait dengan sistem file), periksa: Ringkas dan portabel "gabung" pada baris perintah Unix .

kenorb
sumber
9

Jangan menemukan kembali roda.

ls -m

Itu persis seperti itu.

Tulains Córdova
sumber
OP menginginkan pembatas sehingga Anda masih perlu tr untuk mengonversi koma. Itu juga menambahkan spasi setelah koma yaitu file1, file2, file3
rob
jadi gunakan ls -mdan truntuk menghapus spasi setelah koma yang akan Anda lakukanls -m | tr -d ' '
Andy
2
bahwa penggunaan tr akan menghapus spasi di dalam nama file. lebih baik digunakansed 's/, /,/g
glenn jackman
7

hanya bash

mystring=$(printf "%s|" *)
echo ${mystring%|}
ghostdog74
sumber
5
Agak lebih efisien menggunakan "printf -v mystring"% s | "*" - yang menghindari garpu untuk $ ()
camh
Tapi terutama tidak |mengejar jejak, @camh.
Christopher
1
Nah, adil bashdan gnu printf
coreutils
@camh Tapi printf -vhanya akan bekerja di bash, sedangkan jawaban yang disajikan bekerja pada banyak jenis shell.
Isaac
@ Christopher Ya, yang akan menghapus trailing |, asalkan kedua saluran yang digunakan: printf -v mystring "%s|" * ; echo ${mystring%|}.
Isaac
7

Perintah ini untuk penggemar PERL:

ls -1 | perl -l40pe0

Di sini 40 adalah kode ascii oktal untuk ruang.

-p akan memproses baris demi baris dan mencetak

-l akan mengurus penggantian trailing \ n dengan karakter ascii yang kami sediakan.

-e adalah untuk memberi tahu PERL bahwa kita sedang melakukan eksekusi baris perintah.

0 berarti sebenarnya tidak ada perintah untuk dieksekusi.

perl -e0 sama dengan perl -e ''

Sidharth C. Nadhan
sumber
6

Untuk menghindari kemungkinan kebingungan baris baru untuk tr kita bisa menambahkan flag -b ke ls:

ls -1b | tr '\n' ';'
yabt
sumber
5

Sepertinya jawabannya sudah ada.

Jika Anda ingin a, b, cmemformat, gunakan ls -m( jawaban Tulains Córdova )

Atau jika Anda ingin a b cmemformat, gunakan ls | xargs(versi sederhana jawaban Chris J )

Atau jika Anda ingin pembatas lain seperti |, gunakan ls | paste -sd'|'(aplikasi jawaban Artem )

plhn
sumber
5

Menambahkan di atas jawaban majkinetor, berikut adalah cara menghilangkan pembatas trailing (karena saya belum bisa mengomentari jawabannya):

ls -1 | awk 'ORS=","' | head -c -1

Hapus saja trailing byte yang dihitung oleh pembatas Anda.

Saya suka pendekatan ini karena saya bisa menggunakan pembatas multi-karakter + manfaat lain dari awk:

ls -1 | awk 'ORS=", "' | head -c -2

EDIT

Seperti yang Peter perhatikan, jumlah byte negatif tidak didukung dalam versi kepala MacOS asli. Namun ini dapat dengan mudah diperbaiki.

Pertama, instal coreutils. "Utilitas Inti GNU adalah utilitas manipulasi file, shell dan teks dasar sistem operasi GNU."

brew install coreutils

Perintah yang disediakan oleh MacOS juga diinstal dengan awalan "g". Sebagai contoh gls.

Setelah Anda melakukan ini, Anda dapat menggunakan gheadyang memiliki jumlah byte negatif, atau lebih baik, buat alias:

alias head="ghead"
Aleksander Stelmaczonek
sumber
Catatan: jumlah byte negatif hanya didukung pada versi kepala tertentu, jadi ini tidak akan berfungsi pada mis. Makro.
Peter
Terima kasih, untuk menunjukkannya. Saya telah menambahkan solusi untuk MacOS.
Aleksander Stelmaczonek
4

Cara sed,

sed -e ':a; N; $!ba; s/\n/,/g'
  # :a         # label called 'a'
  # N          # append next line into Pattern Space (see info sed)
  # $!ba       # if it's the last line ($) do not (!) jump to (b) label :a (a) - break loop
  # s/\n/,/g   # any substitution you want

Catatan :

Ini linear dalam kompleksitas, menggantikan hanya sekali setelah semua baris ditambahkan ke Pola Space.

@ AnandRajaseka menjawab , dan beberapa jawaban serupa lainnya, seperti di sini , adalah O (n²), karena sed harus melakukan penggantian setiap kali baris baru ditambahkan ke Pola Space.

Untuk membandingkan,

seq 1 100000 | sed ':a; N; $!ba; s/\n/,/g' | head -c 80
  # linear, in less than 0.1s
seq 1 100000 | sed ':a; /$/N; s/\n/,/; ta' | head -c 80
  # quadratic, hung
zhazha
sumber
3

Jika versi xargs Anda mendukung flag -d maka ini akan berfungsi

ls  | xargs -d, -L 1 echo

-d adalah bendera pembatas

Jika Anda tidak memiliki -d, maka Anda dapat mencoba yang berikut ini

ls | xargs -I {} echo {}, | xargs echo

Xargs pertama memungkinkan Anda untuk menentukan pembatas yang merupakan koma dalam contoh ini.

Chris J
sumber
3
-dmenentukan pembatas input dengan GNU xargs, jadi tidak akan berfungsi. Contoh kedua menunjukkan masalah yang sama dengan solusi lain di sini dari pembatas tersasar pada akhirnya.
Thor
3
sed -e :a -e '/$/N; s/\n/\\n/; ta' [filename]

Penjelasan:

-e- menunjukkan perintah yang akan dieksekusi
:a- adalah label
/$/N- mendefinisikan ruang lingkup kecocokan untuk arus dan (ext) garis
s/\n/\\n/;- menggantikan semua EOL dengan \n
ta;- label goto a jika pertandingan berhasil

Diambil dari blog saya .

Anand Rajasekar
sumber
2

Kamu bisa menggunakan:

ls -1 | perl -pe 's/\n$/some_delimiter/'
codaddict
sumber
Ini tidak mengecualikan pembatas trailing.
Derek Mahar
2

lsmenghasilkan satu output kolom ketika terhubung ke pipa, sehingga -1redundan.

Inilah jawaban perl lainnya menggunakan joinfungsi builtin yang tidak meninggalkan pembatas trailing:

ls | perl -F'\n' -0777 -anE 'say join ",", @F'

Yang tidak jelas -0777membuat perl membaca semua input sebelum menjalankan program.

sed alternatif yang tidak meninggalkan pembatas trailing

ls | sed '$!s/$/,/' | tr -d '\n'
Thor
sumber
0

lsmemiliki opsi -muntuk membatasi output dengan ", "koma dan spasi.

ls -m | tr -d ' ' | tr ',' ';'

perpipaan hasil ini truntuk menghilangkan spasi atau koma akan memungkinkan Anda untuk menyalurkan hasilnya lagi truntuk mengganti pembatas.

dalam contoh saya, saya mengganti pembatas ,dengan pembatas;

ganti ;dengan pembatas satu karakter apa pun yang Anda sukai karena tr hanya menghitung karakter pertama dalam string yang Anda berikan sebagai argumen.

Andy
sumber
0

Anda dapat menggunakan chomp untuk menggabungkan beberapa baris dalam satu baris:

perl -e 'while (<>) {if (/ \ $ /) {chomp; } print;} 'bad0> test

menempatkan kondisi garis istirahat di if pernyataan. Ini dapat berupa karakter khusus atau pembatas apa pun.

Suman
sumber
0

Versi Perl cepat dengan penanganan garis miring:

ls -1 | perl -E 'say join ", ", map {chomp; $_} <>'

Untuk menjelaskan:

  • perl -E: jalankan Perl dengan fitur-fitur yang mendukung (katakanlah, ...)
  • katakan: cetak dengan pengembalian pembawa
  • bergabung dengan ",", ARRAY_HERE: bergabung dengan array dengan ","
  • map {chomp; $ _} ROWS: hapus dari setiap baris operator kembali dan mengembalikan hasilnya
  • <>: stdin, setiap baris adalah ROW, ditambah dengan peta itu akan membuat array dari setiap ROW
Celogeek San
sumber