Command Line - PowerShell - Windows

Coreutils per Windows: usare grep e gli strumenti Linux in PowerShell

Microsoft ha annunciato il rilascio di Coreutils per Windows, oltre 100 strumenti da riga di comando Unix (grep, cat, ls, sort, wc e molti altri) ora disponibili nativamente su Windows, installabili con un singolo comando e integrabili direttamente nella pipeline di PowerShell.

Cosa sono i Coreutils

I Coreutils sono una raccolta di utility fondamentali nate nell’ecosistema Unix: strumenti come grep, cat, ls, cp, mv, rm, head, tail, sort, wc, tee, find, hostname, pwd, sleep, uptime e molti altri. Su Linux e macOS sono presenti di default in qualsiasi distribuzione mentre su Windows non esisteva un equivalente ufficiale.

Come si installa

L’installazione avviene tramite winget, il package manager integrato in Windows 10 (dalla build 1809) e Windows 11

winget install Microsoft.Coreutils

Il comando scarica il pacchetto, lo installa in C:\Program Files\Coreutils che contiene questa struttura

C:\Program Files\Coreutils\
├── coreutils.exe          ← il binario principale
├── bin\                   ← eseguibili .exe aggiunti al PATH
│   ├── grep.exe
│   ├── cat.exe
│   ├── sort.exe
│   └── ...
└── cmd\                   ← varianti .cmd (stesso contenuto)
    ├── grep.cmd
    ├── sort.cmd
    └── ...

La cartella bin\ viene aggiunta automaticamente al PATH dell’utente.

Un dettaglio architetturale interessante riguarda come sono strutturati questi file. Anziché avere un eseguibile separato per ogni comando, esiste un solo filecoreutils.exe. Tutti i file in bin\ e cmd\ sono hardlink NTFS che puntano allo stesso contenuto su disco, motivo per cui pesano tutti esattamente la stessa dimensione

Quando si digita grep, Windows esegue coreutils.exe passandogli come informazione il nome con cui è stato chiamato. coreutils.exe legge quel nome e si comporta di conseguenza: se è stato chiamato grep, fa grep; se è stato chiamato cat, fa cat. Il risultato pratico è che l’intera suite di oltre 100 comandi occupa su disco lo spazio di un singolo eseguibile.

Coreutils e PowerShell: come funziona l’integrazione

I Coreutils si integrano nella pipeline di PowerShell come qualsiasi altro eseguibile esterno. PowerShell converte automaticamente gli oggetti in testo prima di passarli al tool e il risultato torna nella pipeline come array di stringhe. Di seguito alcuni esempi.

Filtrare i processi con grep

$Coreutils = Get-Process | grep cmd
$Coreutils

# Output atteso
     10     6,18       9,87       0,09    2068   3 cmd

Get-Process restituisce tutti i processi attivi; grep cmd filtra solo le righe che contengono la stringa cmd. Utile per verificare rapidamente se un processo specifico è in esecuzione senza dover costruire un filtro con Where-Object

Cercare errori in un file di log con grep

grep -i "error" C:\Logs\app.log

# Output atteso
2026-06-11 08:14:22 [ERROR] Connection timeout on host db01
2026-06-11 09:03:45 [ERROR] Failed to write to disk

Il flag -i rende la ricerca case-insensitive. Per cercare più pattern contemporaneamente si usa -E

grep -E "error|warning|critical" C:\Logs\app.log

Il comando è equivalente di Select-String in PowerShell, ma grep è più immediato

Contare le righe di output con wc

Get-Service | wc -l

# Output atteso
290

wc -l conta le righe e nell’esempio vengono conteggiati tutti i servizi presenti nel sistema

Get-Process | grep -i chrome | wc -l

Utile per sapere quanti processi, servizi o righe di log soddisfano un criterio senza dover usare Measure-Object

Monitorare un log in tempo reale con tail

tail -f C:\Logs\app.log

tail -f segue il file in scrittura e stampa ogni nuova riga man mano che viene aggiunta esattamente come viene fatto sui sistemi Linux. Questo comando è indispensabile durante il debug di applicazioni o servizi Windows

tail -50 C:\Logs\app.log

permette di visualizzare le ultime 50 righe del file di log

Contare le connessioni attive per indirizzo IP con sort e uniq

Get-NetTCPConnection -State Established | Select-Object -ExpandProperty RemoteAddress | sort.exe | uniq -c | Sort-Object { [int]($_.Trim() -split '\s+')[0] } -Descending

# Output atteso
     20 127.0.0.1
      3 34.120.68.241
      1 13.69.116.109
      1 192.168.0.152
      1 2606:4700::6811:6c6c

In pochi secondi si ottiene una panoramica di quali host hanno più connessioni aperte, utile per individuare comportamenti anomali o processi che mantengono molte sessioni attive.

Il comando è un buon esempio di approccio ibrido: PowerShell si occupa della parte strutturata, filtrare le connessioni per stato ed estrarre il campo RemoteAddress, mentre i Coreutils gestiscono l’elaborazione testuale con sort.exe e uniq -c. Per l’ordinamento finale si torna a Sort-Object perché, a differenza di sort.exe, sa interpretare correttamente i numeri con spaziatura variabile prodotti da uniq -c

Scrivere su file e schermo contemporaneamente con tee

Get-Process | grep -i cmd | tee C:\Logs\cmd-process.txt

# Output atteso
     10     6,17       9,88       0,06    6684   3 cmd

tee duplica l’output. Lo mostra a schermo e lo scrive nel file specificato. Utile quando si vuole tenere traccia dell’output di un comando senza rinunciare alla visibilità in tempo reale nel terminale

Tipo restituito: array di stringhe

Un aspetto tecnico da comprendere bene è il tipo di dato restituito quando un tool Coreutils si trova nella pipeline di PowerShell

$Coreutils = Get-Process | grep chrome
$Coreutils

# Output atteso
     23    23,27      48,47       0,27    1096   3 chrome
     67    75,56     217,32       9,34    1284   3 chrome
     20    17,15      42,84       0,19    2088   3 chrome

Il risultato è un array

$Coreutils.GetType()

# Output atteso
IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     String                                   System.Object

Accedendo a un singolo elemento

$Coreutils[0]
$Coreutils[0].GetType()

# Output atteso
     23    23,27      48,47       0,27    1096   3 chrome

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     String                                   System.Object

$Coreutils[1]

# Output atteso
     67    75,56     217,32       9,34    1284   3 chrome

possiamo vedere che ogni elemento è una stringa, non un oggetto strutturato come quelli prodotti nativamente dai cmdlet PowerShell. Il motivo è semplice: i tool Unix lavorano su testo, non su oggetti tipizzati. La serializzazione avviene già a monte, quando PowerShell converte gli oggetti Process in rappresentazione testuale prima di passarli alla pipe

Conflitti con alias e comandi esistenti

Alcuni nomi dei Coreutils collidono con alias o cmdlet nativi di PowerShell. Ad esempio, sort in PowerShell è già un alias per Sort-Object, e ls è un alias per Get-ChildItem. Il comportamento dipende da tre fattori

  • La shell in uso: CMD e PowerShell hanno tabelle di comandi diverse
  • L’ordine del PATH: il sistema esegue il primo eseguibile trovato nella sequenza di directory del PATH
  • La tabella degli alias di PowerShell: gli alias hanno precedenza sugli eseguibili nel PATH

Possiamo forzare l’esecuzione della versione Coreutils quando esiste un conflitto

Aggiungere l’estensione .exe: il metodo più rapido, ideale dentro one-liner. PowerShell risolve gli alias solo sui nomi senza estensione mentre specificando .exe si salta direttamente all’eseguibile

sort.exe file.txt

Usare il percorso completo: utile quando si vuole essere espliciti o si lavora in contesti dove il PATH potrebbe variare

& "$env:ProgramFiles\Coreutils\bin\sort.exe" -r -n file.txt

Per verificare quale versione di un comando viene effettivamente eseguita

Get-Command grep | Select-Object -ExpandProperty Source

# Output atteso
C:\Program Files\coreutils\bin\grep.exe

Coreutils vs cmdlet nativi PowerShell

Chi inizia a usare PowerShell e conosce già Linux potrebbe chiedersi: perché usare grep invece di Select-String? Perché wc -l invece di Measure-Object? La risposta è che non si tratta di scegliere uno strumento migliore dell’altro, ma di capire come lavorano in modo diverso.

La differenza fondamentale è che PowerShell ragiona per oggetti mentre i Coreutils ragionano per testo. Quando usare uno, quando usare l’altro?

  • Usare i cmdlet nativi quando si ha bisogno di lavorare con i dati in modo strutturato: filtrare per valore numerico, esportare in CSV, concatenare operazioni complesse, o quando la precisione conta più della velocità di scrittura
  • Usare i Coreutils quando si vuole una risposta rapida, si sta leggendo un file di log, si sta monitorando output in tempo reale. Sono anche la scelta naturale per script che devono girare sia su Windows che su Linux senza modifiche