export-csv — Write PowerShell objects to a CSV file with header row across all 5 shells
Equivalents in every shell
echo -e "name,age\nalice,30\nbob,25" > users.csvBash has no built-in CSV writer — `printf` or `echo -e` with literal `\n` is the lowest-common-denominator approach. For programmatic CSV, `mlr --c2t cat` (Miller) or `csvkit`'s `csvjson --reverse` give safer escaping (quotes around fields containing commas / newlines / quotes per RFC 4180).
echo -e "name,age\nalice,30\nbob,25" > users.csvSame approach. macOS `echo` accepts `-e` since Big Sur (bash 3.2 builtin); on older macOS, prefer `printf "name,age\nalice,30\n"` for portability. Install `mlr` via `brew install miller` for safer typed CSV emission.
printf "name,age\nalice,30\nbob,25\n" > users.csvFish has no `echo -e` (it doesn't interpret backslash escapes by default). Use `printf` for literal newlines, or `string join \n` if generating lines from a fish list.
$users | Export-Csv -Path users.csv -NoTypeInformation`-NoTypeInformation` suppresses the `#TYPE System.Management.Automation.PSCustomObject` header line — on pwsh 6+ this is the DEFAULT, but on Windows PowerShell 5.1 the type header is included by default and breaks every other CSV consumer (Excel, pandas, csvkit). Always pass the flag for portable scripts.
powershell -NoProfile -Command "$users | Export-Csv users.csv -NoTypeInformation"cmd.exe has no CSV writer. PowerShell shell-out is the standard answer. For pure-cmd one-offs, `echo name,age > users.csv` + `echo alice,30 >> users.csv` works but doesn't handle quoting or escapes.
Worked examples
Export a list of running processes to CSV
ps -eo pid,user,cmd --no-headers | awk 'BEGIN{print "pid,user,cmd"} {print $1","$2","$3}' > procs.csvGet-Process | Select-Object Id, ProcessName, CPU | Export-Csv procs.csv -NoTypeInformationAppend to an existing CSV without rewriting the header
echo "carol,28" >> users.csv$newUser | Export-Csv users.csv -Append -NoTypeInformationUse a semicolon delimiter (Excel-EU friendly)
mlr --ocsvlite --ofs ";" cat users.json > users.csv$users | Export-Csv users.csv -Delimiter ";" -NoTypeInformationGotchas
- **Windows PowerShell 5.1 mandatorily emits `#TYPE …` as line 1** unless `-NoTypeInformation` is passed — every downstream tool (Excel, pandas, R) treats it as garbage. pwsh 6+ flipped the default to omit, but the flag is still accepted for back-compat. Make `-NoTypeInformation` muscle memory on 5.1 scripts.
- `-Append` does NOT check that the header row matches the existing file — if the appended objects have different / extra properties, you get rows with shifted columns. Always materialise the target schema first (`Select-Object Id, Name, ...`) before piping to `-Append`.
- Default encoding on Windows PowerShell 5.1 is `default` (Windows-1252 on US locales, MBCS elsewhere) — non-ASCII data round-trips lossily. Pass `-Encoding utf8` (or `utf8NoBOM` on pwsh 6+) for safe Unicode. pwsh 6+ defaults to `utf8NoBOM`.
- `-UseQuotes` (pwsh 7+) controls quoting: `Never` / `Always` / `AsNeeded` (default — quotes only fields containing delimiter / newline / quote). 5.1 + 6.x always quote-every-field — Excel-EU CSV consumers sometimes choke on this.
- Concurrent `-Append` from multiple processes is NOT safe — the cmdlet opens the file with default share flags and you get interleaved-row corruption. For concurrent writers, serialise via a queue (Service Bus, file lock) or write per-process files and combine afterwards.