Ders 13 / 20
Komut Satırı Uygulamaları
Seçenek ayrıştırma, girdinin dosyadan ya da boru hattından alınması, terminale bağlılık denetimi, kullanım metninin doğru akışa yazılması ve anlamlı çıkış kodları.
İçindekiler
Yerleşik modüller konusu, ölçüm toplayıcının bütün yapı taşlarını kurdu. Hizmet biçimi ise tek kullanım biçimi değildir: aynı özetleme mantığı, bir boru hattına takılabilen komut satırı aracı olarak da işe yarar — bir kütük dosyasını hızla incelemek, bir sunucuyu ayağa kaldırmayı gerektirmemelidir.
Bu ders o aracı yazar. Kabuk Programlama kursundaki süzgeç modeli ölçüt olacak: argümanları tanımlı biçimde alan, girdisini dosyadan ya da boru hattından okuyan, verisini birinci akışa, açıklamalarını ikinci akışa yazan ve sonucu çıkış koduyla bildiren bir araç.
Seçenekleri Ayrıştırmak
process.argv dizisini elle taramak, üçüncü seçenekten sonra hataya açık hâle gelir:
kısa ve uzun biçim, değer ayracı, birleşik bayraklar, -- sonrası argümanlar.
node:util modülündeki parseArgs, bu kuralları tanımlı bir biçimde uygular. İşlev
belirli bir sürümden itibaren kararlı sayılır; daha eski bir çalışma zamanı hedefliyorsanız
varlığını sınamanız gerekir.
Ayrıştırıcıya her seçeneğin türü ve varsayılanı bildirilir. strict kipinde tanımsız
bir seçenek hata fırlatır; bu, yazım yanlışının sessizce yok sayılmasını engeller.
#!/usr/bin/env node // topla.mjs import { parseArgs } from 'node:util'; import { createReadStream } from 'node:fs'; import { createInterface } from 'node:readline'; import { Ozetleyici, satirdanKayit } from './ozetleyici.mjs'; const KULLANIM = `kullanim: topla.mjs [--dosya YOL] [--metrik AD] [--bicim metin|json] --dosya olcum dosyasi; verilmezse standart girdi okunur --metrik yalnizca bu metrigi ozetle --bicim cikti bicimi: metin veya json (varsayilan: metin) --yardim bu metni yaz ve cik `; function seceneklerdenOku(argumanlar) { const { values } = parseArgs({ args: argumanlar, options: { dosya: { type: 'string' }, metrik: { type: 'string' }, bicim: { type: 'string', default: 'metin' }, yardim: { type: 'boolean', default: false }, }, strict: true, }); if (!['metin', 'json'].includes(values.bicim)) { throw new TypeError(`--bicim yalnizca metin veya json olabilir, gelen: ${values.bicim}`); } return values; } let secenekler; try { secenekler = seceneklerdenOku(process.argv.slice(2)); } catch (hata) { process.stderr.write(`${hata.message}\n\n${KULLANIM}`); process.exit(2); } if (secenekler.yardim) { process.stdout.write(KULLANIM); process.exit(0); } const girdi = secenekler.dosya ? createReadStream(secenekler.dosya) : process.stdin; if (!secenekler.dosya && process.stdin.isTTY) { process.stderr.write(`girdi yok\n\n${KULLANIM}`); process.exit(2); } const ozetleyici = new Ozetleyici(); let okunan = 0; let atlanan = 0; try { for await (const satir of createInterface({ input: girdi, crlfDelay: Infinity })) { if (satir.trim() === '') continue; okunan += 1; let kayit; try { kayit = satirdanKayit(satir); } catch { atlanan += 1; continue; } if (secenekler.metrik && kayit.metrik !== secenekler.metrik) continue; ozetleyici.ekle(kayit); } } catch (hata) { process.stderr.write(`girdi okunamadi: ${hata.code ?? hata.message}\n`); process.exitCode = 66; } const ozet = ozetleyici.ozet(); if (secenekler.bicim === 'json') { process.stdout.write(JSON.stringify(ozet) + '\n'); } else { for (const s of ozet) { process.stdout.write(`${s.anahtar}\t${s.sayi}\t${s.ortalama}\t${s.enBuyuk}\n`); } } process.stderr.write(`${okunan} satir okundu, ${atlanan} satir atlandi\n`);
Araç, HTTP Sunucusu dersinde yazılan ozetleyici.mjs modülünü olduğu gibi kullanır.
Aynı doğrulama ve aynı birikim iki arayüzde de geçerlidir; bu, mantığın sunucudan
ayrı bir modülde tutulmasının karşılığıdır.
node topla.mjs --dosya olcumler.ndjson
kenar-01/sicaklik 3 21.87 22.3 kenar-01/nem 2 47.6 48 kenar-02/sicaklik 3 20.23 20.7 kenar-02/nem 1 52.5 52.5 kenar-03/sicaklik 2 24.35 24.6 kenar-03/nem 1 41.3 41.3 12 satir okundu, 0 satir atlandi
Son satır standart hataya yazıldı; onu ayırt etmek için akışlardan birini yönlendirmek yeterlidir.
Girdinin İki Kaynağı
Kabuk Programlama kursunda süzgeçler üç öbeğe ayrılmıştı; üçüncü öbek hem dosya adı
hem standart girdi kabul eder. Yukarıdaki araç bu öbektendir: --dosya verilmezse
process.stdin okunur.
cat olcumler.ndjson | node topla.mjs --metrik sicaklik --bicim json
[{"anahtar":"kenar-01/sicaklik","sayi":3,"ortalama":21.87,"enBuyuk":22.3},{"anahtar":"kenar-02/sicaklik","sayi":3,"ortalama":20.23,"enBuyuk":20.7},{"anahtar":"kenar-03/sicaklik","sayi":2,"ortalama":24.35,"enBuyuk":24.6}]
12 satir okundu, 0 satir atlandi
Satır satır okuma node:readline arayüzüyle yapılıyor. Bu arayüz, akışlar dersinde
elle yazılan satır bölme işini üstlenir ve geri basıncı korur: döngü gövdesi
çalışırken kaynak duraklar. Dosyanın tamamı hiçbir zaman belleğe alınmaz.
crlfDelay: Infinity seçeneği, \r\n ikilisini tek satır sonu sayar. Farklı
platformlarda üretilmiş dosyalar okunacaksa bu ayar gereklidir.
Aracın çıktısı yine bir boru hattına verilebilir:
node topla.mjs --dosya olcumler.ndjson 2>/dev/null | sort -t$'\t' -k3 -n -r | head -3
kenar-02/nem 1 52.5 52.5 kenar-01/nem 2 47.6 48 kenar-03/nem 1 41.3 41.3
Sekmeyle ayrılmış sütun biçimi bu bileşim için seçildi. JSON biçimi programla işlenecek çıktı içindir; sütun biçimi ise Kabuk Programlama kursundaki alan tabanlı araçlarla doğrudan çalışır.
Terminale Bağlılık Denetimi
Standart girdi bir terminale bağlıysa ve kullanıcı dosya adı vermediyse, program sessizce beklemeye başlar. Kullanıcı için bu bir donma gibi görünür.
process.stdin.isTTY alanı, akışın bir terminale bağlı olup olmadığını bildirir.
Boru hattına bağlı bir çalıştırmada değer tanımsızdır:
// tty.mjs console.log('stdout terminale mi bagli:', Boolean(process.stdout.isTTY)); console.log('stdin terminale mi bagli:', Boolean(process.stdin.isTTY));
node tty.mjs | cat
stdout terminale mi bagli: false stdin terminale mi bagli: false
Aynı betik doğrudan bir uçbirimde çalıştırıldığında iki satır da true yazar.
Bu denetim yalnızca donmayı önlemek için değil, çıktı biçimini seçmek için de kullanılır: çıktı terminaldeyse renk ve hizalama eklenebilir, bir dosyaya veya boruya gidiyorsa eklenmemelidir. Çünkü renk kaçış dizileri veriye karışır ve bir sonraki komut onları alan içeriği sanır.
Hataları Ayırmak
Aracın üç hata durumu vardır ve üçü ayrı kodlarla bildirilir.
Tanınmayan seçenek, kullanım hatasıdır:
node topla.mjs --bilinmeyen; echo "cikis kodu: $?"
Unknown option '--bilinmeyen' kullanim: topla.mjs [--dosya YOL] [--metrik AD] [--bicim metin|json] --dosya olcum dosyasi; verilmezse standart girdi okunur --metrik yalnizca bu metrigi ozetle --bicim cikti bicimi: metin veya json (varsayilan: metin) --yardim bu metni yaz ve cik cikis kodu: 2
Girdinin okunamaması ayrı bir durumdur ve ayrı bir kod alır:
node topla.mjs --dosya yok.ndjson; echo "cikis kodu: $?"
girdi okunamadi: ENOENT 0 satir okundu, 0 satir atlandi cikis kodu: 66
Tek tek bozuk satırlar ise hata değildir; sayılır ve atlanır:
node topla.mjs --dosya bozuk.ndjson
kenar-01/nem 1 48 48 kenar-02/nem 1 50 50 3 satir okundu, 1 satir atlandi
Bu ayrım bilinçlidir. Toplu ölçüm verisinde tek bir bozuk satır yüzünden bütün raporu düşürmek, verinin tamamını kullanılamaz kılar; buna karşılık atlanan satır sayısı sessizce gizlenmemeli, tanı akışına yazılmalıdır.
Kullanım metni standart hataya yazılıyor, çünkü bir hatanın parçasıdır. --yardim
seçeneğiyle istendiğinde ise standart çıktıya yazılır ve çıkış kodu sıfırdır: orada
kullanım metni istenen sonucun kendisidir.
Dosyanın ilk satırındaki yorumlayıcı bildirimi ile çalıştırma izni verildiğinde araç doğrudan çağrılabilir:
./topla.mjs --dosya olcumler.ndjson --metrik nem
kenar-01/nem 2 47.6 48 kenar-02/nem 1 52.5 52.5 kenar-03/nem 1 41.3 41.3 12 satir okundu, 0 satir atlandi
Özet
- Yerleşik seçenek ayrıştırıcı, seçenek adlarını ve türlerini bildirime dayalı olarak alır; katı kip tanımsız seçeneği hata sayar ve yazım yanlışını yakalar.
- Aynı özetleme modülü hem hizmette hem komut satırı aracında kullanılır; mantığın arayüzden ayrılmasının karşılığı budur.
- Girdi dosyadan veya standart girdiden alınır; satır satır okuma geri basıncı korur ve dosyayı belleğe almaz.
- Terminale bağlılık denetimi hem beklemeyi önler hem de çıktı biçimini seçmeye yarar; renk kaçışları boru hattında veriye karışır.
- Kullanım hatası, girdi hatası ve tek tek bozuk kayıtlar ayrı ele alınır; ilk ikisi ayrı çıkış kodlarıyla, üçüncüsü sayaçla bildirilir.
Sonraki Adım
Araçta ve hizmette hâlâ sabit yazılmış değerler var: dosya adı, bağlantı noktası, gövde boyutu sınırı. Bunlar çalıştığı ortama göre değişmeli, ama kaynak kodu değişmemelidir. Sonraki ders yapılandırma yönetimini ele alır: değerlerin nereden okunacağı, nasıl doğrulanacağı ve gizli değerlerin sıradan ayarlardan neden ayrı tutulması gerektiği.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.