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.CoreutilsIl 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 file: coreutils.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 cmdGet-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 diskIl flag -i rende la ricerca case-insensitive. Per cercare più pattern contemporaneamente si usa -E
grep -E "error|warning|critical" C:\Logs\app.logIl comando è equivalente di Select-String in PowerShell, ma grep è più immediato
Contare le righe di output con wc
Get-Service | wc -l
# Output atteso
290wc -l conta le righe e nell’esempio vengono conteggiati tutti i servizi presenti nel sistema
Get-Process | grep -i chrome | wc -lUtile 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.logtail -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.logpermette 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:6c6cIn 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 cmdtee 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 chromeIl risultato è un array
$Coreutils.GetType()
# Output atteso
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True String System.ObjectAccedendo 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 chromepossiamo 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.txtUsare 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.txtPer verificare quale versione di un comando viene effettivamente eseguita
Get-Command grep | Select-Object -ExpandProperty Source
# Output atteso
C:\Program Files\coreutils\bin\grep.exeCoreutils 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