Saya memiliki dua file teks: string.txt dan lengths.txt
String.txt:
abcdefghijklmnopqrstuvwxyz
lengths.txt
5
4
10
7
Saya ingin mendapatkan file
>Entry_1
abcde
>Entry_2
fghi
>Entry_3
jklmnopqrs
>Entry_4
tuvwxyz
Saya bekerja dengan sekitar 28.000 entri dan mereka bervariasi antara 200 dan 56.000 karakter.
Saat ini, saya menggunakan:
start=1
end=0
i=0
while read read_l
do
let i=i+1
let end=end+read_l
echo -e ">Entry_$i" >>outfile.txt
echo "$(cut -c$start-$end String.txt)" >>outfile.txt
let start=start+read_l
echo $i
done <lengths.txt
Tetapi ini sangat tidak efisien. Ada ide yang lebih baik?
linux
shell-script
pengguna3891532
sumber
sumber
str="$(cat string.txt)"; i=0; while read j; do echo "${file:$i:$j}"; i=$((i+j)); done <length.txt
sepertinya cukup cepat seperti yang dilakukan oleh shell ..{ while read l<&3; do head -c"$l"; echo; done 3<lengths.txt; } <String.txt
.Jawaban:
Anda dapat melakukan
Dibutuhkan beberapa penjelasan:
Gagasan utamanya adalah menggunakan
{ head ; } <file
dan diturunkan dari jawaban @mikeserv yang diremehkan . Namun dalam hal ini kita perlu menggunakan banyakhead
s, sehinggawhile
loop diperkenalkan dan sedikit penyesuaian dengan deskriptor file untuk meneruskan kehead
input dari kedua file (fileString.txt
sebagai file utama untuk diproses dan baris darilength.txt
sebagai argumen ke-c
opsi) . Idenya adalah bahwa manfaat dalam kecepatan harus datang dari tidak perlu mencari melaluiString.txt
setiap kali perintah sukahead
ataucut
dipanggil. Theecho
hanya untuk mencetak baris baru setelah setiap iterasi.Betapa lebih cepat (jika ada) dan menambahkan di
>Entry_i
antara baris dibiarkan sebagai latihan.sumber
read -u 3
untuk membaca dari deskriptor 3.bash
. Sebagian besar sistem berbasis Linux tidakbash
diinstal (pikirkan Android dan sistem tertanam lainnya).bash
menjadi shell paling lambat dari semuanya, beralih ke bash kemungkinan akan menurunkan kinerja lebih signifikan daripada keuntungan kecil yang dibawa dari beralihread <&3
keread -u3
(yang dalam hal apa pun akan tidak signifikan dibandingkan dengan biaya menjalankan perintah eksternal sepertihead
). Beralih ke ksh93 yang memilikihead
builtin (dan yang mendukung opsi non-standar-c
) akan meningkatkan kinerja lebih banyak.head -c
(untukhead
implementasi di mana opsi non-standar tersedia) adalah sejumlah byte, bukan karakter. Itu akan membuat perbedaan dalam multi-byte locales.Secara umum, Anda tidak ingin menggunakan shell loop untuk memproses teks . Di sini, saya akan menggunakan
perl
:Itu satu perintah, yang berbunyi (dengan buffering jadi jauh lebih efisien daripada perintah shell
read
yang membaca satu byte (atau beberapa byte untuk file biasa) sekaligus) kedua file hanya sekali (tanpa menyimpannya dalam memori penuh), begitu juga akan ada beberapa urutan besarnya lebih efisien daripada solusi yang menjalankan perintah eksternal dalam satu loop shell.(tambahkan
-C
opsi jika angka-angka itu haruslah jumlah karakter di lokal saat ini sebagai lawan dari jumlah byte. Untuk karakter ASCII seperti dalam sampel Anda, itu tidak akan membuat perbedaan).sumber
$_
sebagai parameter output dan inputread
, tetapi mengurangi jumlah byte dalam skrip.bash
, 16 detik denganPATH=/opt/ast/bin:$PATH ksh93
)).bash, versi 4
keluaran
sumber
Bagaimana dengan
awk
?Buat file yang disebut
process.awk
dengan kode ini:Simpan dan jalankan
awk -f process.awk lengths.txt string.txt
sumber
PROCINFO
, ini bukan standarawk
, tetapigawk
. Dalam hal ini saya lebih suka yang laingawk
hanya fitur,FIELDWIDTHS
:awk -vFIELDWIDTHS="$(tr '\n' ' ' < lengths.txt)" '{for(i=1;i<=NF;i++)print">Entry"i ORS$i}' string.txt