İçeriğe geç
academia.sh

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.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat