did you know the existing shell scripts could break in unbelievable ways bc Ubuntu decided to yolo their rust-rewritten components?
coreutils#13970
2 likes · 137 views
Some fixes for uutils awk, uutils coreutils. Got CI fixed in awk and the test-patching env set up, so doing further fixes should much easier now.
3 likes
[AI]
@freya oh and also,
github.com/uutils/coreutils/blob/main/AGENTS.md
1 like
Before You Pipe Microsoft's One-Line Dev Box Setup into iex, Read What It Changes
At Build 2026 Microsoft announced two things that matter if you set up Windows machines for coding: Windows Developer Configurations, a one-command setup for a fresh dev box, and Coreutils for Windows, native builds of ls, cp, grep and friends. Both were announced as generally available.
The setup is one line of PowerShell piped into iex. That is convenient, and it is also exactly the kind of command you should read before running on a machine you care about. So we read the repo docs and the scripts. Here is what actually happens, what changes on your machine, and the parts that could surprise you.
TL;DR
- irm https://aka.ms/devconfig/standard/setup.ps1 | iex installs about 18 packages with winget, changes Explorer, Start, search and theme settings, installs WSL with Ubuntu, and may restart your PC once.
- Standard runs the bootstrap with -Action Partial. Full runs -Action Full and adds Developer Mode, Sudo, widgets off, two Edge policies and Remote Desktop.
- The scripts verify Microsoft Authenticode signatures on everything they download, but irm | iex itself does not verify the small wrapper script. You can check it yourself first.
- The uninstall script permanently deletes the Ubuntu distro without asking, and it removes the tools it manages even if you had them installed before.
- Coreutils for Windows installs with winget install Microsoft.Coreutils. In PowerShell several commands clash with built-in aliases, which matters for scripts.
The one-liners
From the WindowsDeveloperConfig repo:
# Standard experience
irm https://aka.ms/devconfig/standard/setup.ps1 | iex
# Full experience
irm https://aka.ms/devconfig/full/setup.ps1 | iex
# Uninstall (covers both)
irm https://aka.ms/devconfig/standard/uninstall.ps1 | iex
The aka.ms links redirect to setup-standard.ps1, setup-full.ps1 and uninstall.ps1 in the repo. Each wrapper is about 20 lines. It downloads bootstrap.ps1 from a pinned commit, checks that the signer is Microsoft Corporation, and only then runs it with -Action Partial, -Action Full or -Action Uninstall.
The repo is honest about the gap: "irm | iex does not verify the wrapper's own signature; it trusts the HTTPS endpoint." If you want to check the entry script too, download it and look before you run anything:
$f = "$env:TEMP\setup-standard.ps1"
Invoke-WebRequest https://aka.ms/devconfig/standard/setup.ps1 -OutFile $f
Get-AuthenticodeSignature $f | Format-List Status, SignerCertificate
notepad $f
It is short enough to read in a minute, and it is a good habit for any irm | iex install, not just this one.
What gets installed
The Standard setup installs these with winget:
| Area | Packages |
|---|---|
| Shell and terminal | Windows Terminal, Intelligent Terminal, PowerShell 7, Oh My Posh |
| Source control | Git, GitHub CLI |
| Editors and AI | VS Code, GitHub Copilot CLI |
| Runtimes | .NET SDK 10, Python 3.14 + uv, Node.js LTS + nvm for Windows |
| Cloud | Azure CLI |
| Utilities | Coreutils for Windows, Windows App CLI, PowerToys, Visual C++ Redistributable |
It then sets PowerShell 7 as the default Terminal profile, installs Cascadia Code NF and Cascadia Mono NF for all users, adds a GitHub Copilot profile to the Terminal dropdown, and installs WSL plus Ubuntu with wsl --install -d Ubuntu --no-launch.
Practical numbers from the docs: roughly 30 minutes on a clean machine, about 15 GB of free disk space, up to two UAC prompts, and Windows 11 only. Windows 10 is not supported.
What it changes on your machine
This is the part worth reading twice. Some highlights from the documented registry changes and the "Known limitations" table:
- Explorer: file extensions and hidden files shown, full path in the title bar, Explorer opens to This PC, no recent or frequent items in Quick Access.
- Start and search: no web results in search, no Start recommendations, no search highlights.
- Notifications: Do Not Disturb is turned on globally, not just for quiet hours, until you turn it back off.
- Theme: dark mode for apps and the system.
- Long paths: LongPathsEnabled set to 1.
- Node: both Node.js LTS and nvm for Windows get installed. The docs suggest uninstalling Node.js first if you want nvm to own the PATH entry.
- Your PowerShell profile: an Oh My Posh block is added to $PROFILE. If the profile already has other initialization, setup leaves it alone and flags it.
- Terminal settings: settings.json is round-tripped through JSON, so comments are lost. A settings.json.bak is written first.
The Full setup adds more:
- Developer Mode and Sudo (inline mode).
- Widgets turned off through policy.
- Two Edge settings written as policy, so Edge will say it is "managed by your organization".
- Remote Desktop allowed (fDenyTSConnections set to 0). The docs note the firewall rule is not opened, but it is still a change to the machine's security posture.
What it does not do, per the docs: no telemetry, no sign-ins, no credential changes, no Windows Defender changes. Git and the GitHub CLI are installed but not configured, so you still need git config user.name and gh auth login.
There is also no dry run (-WhatIf) and no switch to skip individual packages. If you want a different package list, the documented path is to clone the repo, edit the files under src\windows-dev-config, and run the unsigned source with -AllowUnsigned.
The restart and the uninstall
WSL needs virtualization, so setup may restart the machine. It warns you and restarts after 10 seconds, so save your work before you start. A scheduled task called WindowsDevConfigResume picks the run up after you sign back in. If nothing happens:
Get-ScheduledTask -TaskName WindowsDevConfigResume
Re-running the original one-liner is safe. Steps that are already done report already OK and are skipped. Logs go to devconfig-log.txt under %ProgramData%\CalmOS.
The uninstall deserves a warning of its own. According to the docs it:
- Permanently deletes Ubuntu and its files, without confirmation.
- Removes the tools it manages, including copies you had installed before running setup.
- Resets settings to defaults rather than restoring what you had before (themes go back to light, for example).
If you have real work inside that Ubuntu distro, export it first:
wsl --export Ubuntu D:\backup\ubuntu.tar
Coreutils for Windows
Coreutils for Windows is a Microsoft-maintained build of the Rust uutils projects (coreutils, findutils and grep), shipped as one multi-call binary. It is MIT licensed and has x64 and ARM64 builds. The current release at the time of writing is v2026.9.3. The Standard setup installs it, or you can install it alone:
winget install Microsoft.Coreutils
Then the usual pipelines work in CMD and PowerShell:
grep -rn "TODO" src | wc -l
find . -name "*.log" -mtime +7
A few things we would want to know before relying on it in scripts:
- PowerShell 7.4 or later is required, and 7.6 or later is recommended for ~ support.
- Alias clashes. In PowerShell, cat, cp, ls, mv, pwd, rm, sleep, sort, tee and others share names with built-in aliases. The installer hooks into PSReadLine to rewrite what you type interactively, but it does not remove the aliases. Check what a name resolves to with Get-Command ls -All.
- Some commands are not shipped because they clash with Windows built-ins or need POSIX features: dir, more, whoami, kill and timeout among them. chmod, chown and uname are dropped too.
- No /dev/null. Use NUL, as in find . -name "*.log" > NUL.
- CRLF line endings can still trip byte-oriented tools like uniq.
- You can turn off individual utilities with coreutils-manager disable <utility name>.
One detail that may confuse you: the Build blog calls Coreutils generally available, but the repo README still says "This project is in preview." Treat it like any young tool and test your scripts before switching a team over.
Our take
For a brand new machine or a throwaway VM, the Standard setup is a sensible default, and the signing and pinned-commit design is better than most irm | iex installers. On a machine you already use every day, we would read the settings list first, skip Full unless you actually want Remote Desktop and Edge policies, and back up WSL before you ever touch the uninstall script.
Have you tried Windows Developer Config or Coreutils for Windows on a real machine yet? Did it save you time, or did it change something you had to undo? And would you trust a one-line setup script on your main dev box, or only on a fresh VM?
We first wrote about the Build 2026 developer announcements on Windows Mode.
1 reaction
The error messages a Rust rewrite got subtly wrong: what a black-box probe found in uutils coreutils
---
title: "The error messages a Rust rewrite got subtly wrong: what a black-box probe found in uutils coreutils"
published: true
tags: rust, cli, testing, opensource
---
When you rewrite a command-line tool, the happy path is the easy part. Output for valid input gets compared early and often. Error messages are where rewrites quietly drift: a different wording, a missing file name, a raw (os error 20) instead of the sentence a script or a person expects.
I have been running behave against uutils coreutils, the Rust rewrite of GNU coreutils. behave probes a CLI as a black box (flags from --help, stdin, files, odd inputs), records what the reference tool does, and replays the same cases against the rewrite. I record from GNU 9.12, the release uutils targets.
One probe case added in v0.1.7 is simply "a regular file passed with a trailing slash" (f/). It turned out to be a good bug finder, because every utility has to turn ENOTDIR into a message, and each one does it a little differently.
What it found
All of these were reported upstream with a fix PR and a test:
- cp f/ dest printed Not a directory (os error 20); GNU says cannot stat 'f/': Not a directory (#15691, #15692)
- shred dir said Not a file; GNU says failed to open for writing: Is a directory (#15630, #15631)
- mv missing/ g reported the wrong reason for the source (#15704, #15705)
- ln f/ link blamed the link instead of the source (#15713, #15714)
- mv a missing/b printed only the OS error, no cannot move 'a' to ... (#15721, #15722)
- mv -T f d left the source out of cannot overwrite directory (#15724, #15725)
- paste open and read errors without the file name (#15642)
- sort -c dir exited 0 with no message at all (#15615, fixed in #15616, merged)
And one that is not about messages: mv -n z z fails with 'z' and 'z' are the same file, while GNU skips the move and exits 0, because it never runs the same-file check when it would not replace the target anyway (#15824, #15825).
Why these slip through
None of these are hard to fix. Most patches are a few lines plus a test. They slip through because a rewrite's own test suite tends to assert what the authors thought of, and nobody thinks of cp f/ dest. A black-box recording of the original tool asserts everything it actually does, including the boring corners.
Two lessons from the review rounds:
1. Match the reference release. GNU 9.7 and 9.12 differ in small ways (quoting in tail -v headers), so recording from an old GNU produces false positives.
2. Exact OS error text differs between platforms. Tests that compare full strerror text need to be Unix-only, while the context part (cannot move 'a' to 'b') can be checked everywhere.
Try it
brew install emirmrkaljevic/tap/behave
# or: go install github.com/emirmrkaljevic/behave/cmd/behave@latest
behave probe cp # record the reference (GNU cp)
behave diff behave-cp --impl ./target/release/cp --skip-tag meta # replay against your rewrite
If you are porting a CLI to Rust or Go, I would love to hear which cases behave misses.
uutils coreutils 又又又是 Rust 开发的
uutils/coreutils
2 likes · 922 views
I don’t remember the answer, but the real reason was of course cost.
But now, for pennies, Claude will just…do that for you, in the typesafe language of your choice.
There are whole efforts to do this (like uutils/coreutils), and they leverage coding agents!
2 likes
Ubuntu 26.10 Finishes the Rust Coreutils Switch. What Should Developers Test?
---
title: "Ubuntu 26.10 Finishes the Rust Coreutils Switch. What Should Developers Test?"
published: true
description: "Rust-based cp, mv and rm are only part of Ubuntu 26.10's compatibility story. A practical guide to testing OpenSSL 4, toolchains, CI and upgrade risks."
tags: ubuntu, linux, devops, rust
cover_image: dev-to-uploads.s3.us-east-2.amazonaws.com
---
A deployment script can carry years of undocumented assumptions: a particular cp option, an error string parsed by a build step, or a crypto library loaded through an old interface. Most of the time, those assumptions stay invisible.
Ubuntu 26.10 Stonking Stingray, released on October 15, 2026, gives developers a reason to look for them. Its default cp, mv, and rm now come from Rust-based uutils. It also ships OpenSSL 4, a refreshed language and compiler stack, ROCm 10, and a Linux 7.3-based kernel.
There is a catch: 26.10 is an interim release, supported only through July 2027. That makes the decision different for a CI image, a personal workstation, and a production server.
TL;DR: Ubuntu 26.10 is worth testing, not blindly adopting. Check GNU-versus-uutils behavior, OpenSSL 4 dependencies, and your actual build pipeline. Containers cover userspace regressions; kernel and driver changes need a VM or host. For long-lived production systems, 26.04 LTS remains the sensible default.
Here is the checklist I would use before changing a real workload. The commands are reproducible suggestions, not results from a benchmark I ran.
First, understand what changed in cp, mv, and rm
Ubuntu had already moved many command-line utilities to uutils in earlier releases. The three remaining GNU holdouts — cp, mv, and rm — stayed on GNU in 26.04 LTS because of unresolved compatibility concerns. Canonical says the migration is complete in 26.10.
The language behind a command is usually irrelevant to a shell script. Its observable behavior is not. Consider the things scripts routinely depend on:
- accepted flags and option combinations;
- exit statuses, especially under set -e;
- the precise output of --version and error messages;
- symbolic links, permissions, ownership, and cross-filesystem moves;
- behavior on unusual filenames or non-UTF-8 input.
The uutils project aims to be GNU-compatible. It does not claim every GNU edge case is already identical. An upstream compatibility tracker still lists options such as cp --keep-directory-symlink and mv --no-copy as missing in its September comparison. That is a reason to inspect the packaged version you actually run, not evidence that every installation of 26.10 currently fails those cases.
An independent DevOps Daily comparison tested 162 command cases in an Ubuntu 26.10 beta environment and reported 150 byte-identical captured results and 12 differences. The differences included version identification, Unicode handling, exit codes, partial decoding, and diagnostic wording.
Those are their measurements, not mine; 162 selected cases do not measure the entire compatibility surface.
A ten-minute smoke test that stays inside a temp directory
Start with identity. This is safe to run on the system you intend to test:
cat /etc/os-release | grep -E '^(NAME|VERSION|VERSION_ID)='
for tool in cp mv rm; do
printf '%s: ' "$tool"
"$tool" --version | head -n 1
done
If Ubuntu's prefixed GNU tools are available, the following probe checks option visibility without replacing system binaries. The script prints observations, not predetermined pass/fail claims:
for pair in 'cp --keep-directory-symlink' 'mv --no-copy'; do
read -r tool option <<< "$pair"
for bin in "$tool" "gnu$tool"; do
if ! command -v "$bin" >/dev/null 2>&1; then
printf '%s: not installed\n' "$bin"
elif "$bin" --help 2>&1 | grep -Fq -- "$option"; then
printf '%s: %s listed\n' "$bin" "$option"
else
printf '%s: %s NOT listed\n' "$bin" "$option"
fi
done
done
--help is only an initial check. It cannot establish that an option has correct semantics. Follow it with fixtures from your actual build and deployment workflows.
For a small, non-destructive filesystem comparison, run this in a disposable Ubuntu 26.10 VM or container where gnucp and gnumv are available:
#!/usr/bin/env bash
set -euo pipefail
for bin in cp mv gnucp gnumv; do
command -v "$bin" >/dev/null || {
echo "Missing $bin; cannot compare implementations" >&2
exit 2
}
done
work="$(mktemp -d)"
trap 'rm -rf -- "$work"' EXIT
mkdir -p "$work/input/sub"
printf 'alpha\n' > "$work/input/a.txt"
printf 'beta\n' > "$work/input/sub/b.txt"
for implementation in uutils gnu; do
prefix=''
[[ "$implementation" == gnu ]] && prefix='gnu'
mkdir -p "$work/$implementation"
"${prefix}cp" -R \
"$work/input" \
"$work/$implementation/copied"
"${prefix}mv" \
"$work/$implementation/copied/a.txt" \
"$work/$implementation/moved.txt"
(
cd "$work/$implementation"
find . -type f -exec sha256sum {} + |
LC_ALL=C sort
) > "$work/$implementation.manifest"
done
diff -u \
"$work/uutils.manifest" \
"$work/gnu.manifest"
A zero exit code means this tiny fixture produced matching file paths and content hashes.
It says nothing about ACLs, extended attributes, sparse files, symlink semantics, timestamps, ownership, or error handling. Add those deliberately when your application requires them. You can also capture stdout, stderr, exit codes, and the resulting tree for each case.
One more practical point: a --version check that searches for the string GNU can silently select the wrong branch in a legacy script. Search your repositories for these probes before an upgrade.
!A technical map of Ubuntu 26.10 compatibility checks across shell commands, crypto, language runtimes, kernel and GPU software.
Figure 1. A testing map compiled from Canonical's release notes; it does not represent benchmark results.
OpenSSL 4 may be the harder migration
The Rust switch attracts attention because everyone recognizes cp. OpenSSL 4 deserves at least as much attention if you maintain native software, hardware-security-module integrations, or older TLS infrastructure.
OpenSSL 4 removed the ENGINE API. Ubuntu's 26.10 notes specifically explain that PKCS#11-engine configurations must move to the PKCS#11 provider model.
OpenSSL 4 also removes older interfaces and legacy protocol behavior. These changes are relevant even if your own application never calls the openssl executable directly.
Useful read-only inspection commands are:
openssl version -a
openssl list -providers
Then inspect the OpenSSL configuration used by your application for references to engine_id, dynamic_path, and pkcs11.
Redact secrets before sharing logs. Rebuild native dependencies against the target headers, and test a real TLS handshake or HSM operation. openssl version alone cannot prove application compatibility.
For older systems, this is a more specific question than “Does it support OpenSSL 4?”:
Is a provider available for the key material and algorithms the application actually uses?
Newer toolchains: choose tests that match the dependency
Canonical lists the following in its Ubuntu 26.10 release notes:
| Component | Listed version | A useful regression check |
| --- | --- | --- |
| Python | 3.14.7 | Build a fresh environment, install native wheels, and run the suite |
| Go | 1.27 | go test ./..., go vet ./..., code generation, cross-builds |
| LLVM | 22.1.8 | Rebuild LLVM plugins, generated IR, sanitizers, native extensions |
| .NET | 10.0.112 | Check dotnet --info, restore, build, test, publish, native dependencies |
| ROCm | 10.0 | Check supported GPUs, rebuild AMD SMI users, run actual GPU workloads |
| Kernel | 7.3-based | Test drivers, DKMS, eBPF, virtualization and filesystem behavior |
The version numbers are those listed in the release notes, not a claim about the latest patch currently installed on every updated machine.
ROCm has a particularly concrete breaking boundary: Canonical documents an AMD SMI SONAME change to libamd_smi.so.27, removed deprecated AMD SMI APIs, and removal of rocsparse_indextype_u16.
Software that links to the changed library needs rebuilding. For GPU work, verify the exact device against the supported hardware list before planning a migration.
The Ubuntu release image also uses a 7.3.0-9.9 kernel built from upstream 7.3-rc6. The upstream 7.3 final release arrived after Ubuntu 26.10's release date.
To troubleshoot a driver issue, record uname -r and the installed Ubuntu package rather than just writing “Linux 7.3”.
A container is not a kernel test
You can use a 26.10 container to detect userspace regressions, for example:
docker run --rm ubuntu:26.10 bash -lc \
'cat /etc/os-release | grep VERSION=; cp --version | head -1'
Verify image availability and pin a digest for repeatable CI.
But the container shares its host kernel. uname -r inside that container reports the host kernel, not a separately installed Ubuntu 26.10 kernel.
Kernel modules, DKMS, real device drivers, and most GPU integration problems need a VM or physical test host.
That distinction matters when someone says an upgrade passed “in Docker.” It may have passed only the userspace portion.
There are desktop and operational changes too
Ubuntu 26.10 uses GNOME 51.
It also offers Myna, an optional, not-preinstalled local speech-to-text technology preview: transcription runs on the device rather than sending audio to a network service.
These may matter to workstation users, but neither answers whether a production build is ready to move. Canonical documents both.
On servers, inspect SSH authentication before touching a remote box.
In 26.10, GSSAPI/Kerberos-capable OpenSSH packages are split into the openssh-gssapi family; the ordinary client/server packages do not provide that feature. If access depends on it, stage and test that exact access path first.
Canonical also says upgrades from 26.04 LTS with TPM-backed full-disk encryption were not supported at the initial 26.10 release.
Consult the current known-issues section before any encrypted-system upgrade, because restrictions may be updated during the release lifecycle.
My upgrade decision would depend on the workload
!A decision guide showing Ubuntu 26.04 LTS as a production baseline and Ubuntu 26.10 as a parallel test lane before a staged rollout.
Figure 2. A recommended rollout sequence, not an Ubuntu policy or a guarantee of compatibility.
For a developer laptop, 26.10 is attractive if your hardware and dependencies need the new stack and you are comfortable with a nine-month support window. Save a recovery path first.
For CI, add 26.10 in parallel with the existing image.
Compare builds, packages, automated tests, and shell scripts. Use a container job for userspace; use a VM or host runner when kernel behavior is part of the test.
Do not assume ubuntu-26.10 is a valid GitHub-hosted Actions runner label just because an Ubuntu version exists.
For a production server, my default would remain 26.04 LTS unless there is a specific capability worth the maintenance and migration cost.
Check crypto configuration, SSH/Kerberos, drivers, and a tested rollback path before rollout. An interim release is a poor substitute for a support-lifecycle decision.
The checklist I'd save before upgrading
- Shell compatibility: Inventory the exact command implementations and GNU-only options your scripts use.
- Behavioral testing: Run real shell fixtures under GNU and uutils. Compare side effects, not just output.
- Automation: Find scripts that parse version strings, diagnostic messages, or exit codes.
- OpenSSL 4: Rebuild native integrations and migrate ENGINE-based PKCS#11 configurations.
- Toolchains: Install Python dependencies from scratch. Build and test .NET, Go, and LLVM projects where applicable.
- GPU workloads: Validate ROCm against supported hardware and rebuild affected AMD SMI consumers.
- Kernel compatibility: Test drivers, DKMS, and other kernel-dependent features outside containers.
- System access: Verify Kerberos/GSSAPI authentication and TPM-backed encryption upgrade constraints.
- Rollback readiness: Confirm the nine-month support window and rehearse a recovery procedure.
My practical takeaway is to add Ubuntu 26.10 to the compatibility matrix before making it a default.
Even if you plan to stay on LTS, this release is a useful early warning for assumptions buried in tooling and deployment scripts.
Have you seen a real GNU-versus-uutils incompatibility in a build or deployment?
A small reproducible case — exact command, package version, expected and observed behavior — would make a far more useful comment than a generic upgrade verdict.
References
- Canonical — Ubuntu 26.10 release announcement
- Ubuntu 26.10 release notes (features, breaking changes, known issues)
- uutils coreutils project
- uutils GNU-compatibility issue tracker
- DevOps Daily's independent 162-case test on 26.10 beta
- OpenSSL 4.0 removed APIs
- OpenSSL migration guide
Technical scope: release documentation and community test evidence reviewed October 21, 2026. The shell examples are provided for readers to execute and verify on their own systems; no first-party Ubuntu 26.10 benchmark is claimed in this article.
1 reaction
tail: cannot open '7': when localisation reformats your file names
---
title: "tail: cannot open '7': when localisation reformats your file names"
published: true
tags: rust, i18n, testing, cli
---
Ask uutils tail (the Rust rewrite of GNU coreutils) for a file that doesn't exist and it tells you so. Unless the file is called 007:
$ tail 007 # GNU coreutils 9.12
tail: cannot open '007' for reading: No such file or directory
$ tail 007 # uutils main
tail: cannot open '7' for reading: No such file or directory
1e3 comes back as 1000, 1.50 as 1.5, +5 as 5. Try tail 1e3 on a directory and you get "error reading '1000'".
Where the 7 comes from
uutils translates its messages with Fluent. Every argument goes through a translate! macro, and that macro checks whether the value parses as a number. If it does, it hands Fluent a number instead of a string, so the locale can format it (digit grouping, decimal separator). That's what you want for "3 files failed". It's not what you want for a file name that just happens to look like a number: Fluent prints the number, not the text you typed.
The project already has translate_text! for exactly this, and date and the sort --check "disorder" line were fixed the same way earlier. The tail fix (#15534, merged a few hours after I opened it) switches the call sites that take a file name, tac (#15541) was merged the same day, and nl (#15544) and the shared checksum code behind md5sum/cksum (#15548) were merged the next morning. The same pattern still shows up in dd, sort, shred and in clap's "unexpected argument" error, all listed in #15533.
The general lesson, if you localise a CLI with Fluent or ICU MessageFormat: anything the user typed (paths, operands, input lines) should go in as a string. Let only real counts be numbers.
Catching it automatically
I found this with behave, which probes a command as a black box, records what the original does and replays it against a rewrite. Its generated cases always included "missing file", but with the name does-not-exist.txt, which no number parser will touch. Since v0.1.6 behave probe also adds a missing-file case with the names 007 and 1e3:
✗ missing file named like a number 0008-missing-file-named-like-a-number.yaml
$ tail 007 1e3
stderr:
- $CMD: cannot open '007' for reading: No such file or directory
- $CMD: cannot open '1e3' for reading: No such file or directory
+ $CMD: cannot open '7' for reading: No such file or directory
+ $CMD: cannot open '1000' for reading: No such file or directory
It costs one case per tool and checks something every port that translates its messages can get wrong.
go install github.com/emirmrkaljevic/behave/cmd/behave`latest
# or: brew install emirmrkaljevic/tap/behave
behave probe tail --out spec-tail
behave diff spec-tail --impl ./target/release/tail
---
behave is open source (MIT): emirmrkaljevic/behave · more from me on GitHub
1 reaction · 1 comment
@mateusza @ubuntu One more improvement: coreutils#15418
1 like · 11 views
Mentions
did you know the existing shell scripts could break in unbelievable ways bc Ubuntu decided to yolo their rust-rewritten components? coreutils#13970
Some fixes for uutils awk, uutils coreutils. Got CI fixed in awk and the test-patching env set up, so doing further fixes should much easier now.
[AI] @freya oh and also, github.com/uutils/coreutils/blob/main/AGENTS.md
Before You Pipe Microsoft's One-Line Dev Box Setup into iex, Read What It Changes At Build 2026 Microsoft announced two things that matter if you set up Windows machines for coding: Windows Developer Configurations, a one-command setup for a fresh dev box, and Coreutils for Windows, native builds of ls, cp, grep and friends. Both were announced as generally available. The setup is one line of PowerShell piped into iex. That is convenient, and it is also exactly the kind of command you should read before running on a machine you care about. So we read the repo docs and the scripts. Here is what actually happens, what changes on your machine, and the parts that could surprise you. TL;DR - irm https://aka.ms/devconfig/standard/setup.ps1 | iex installs about 18 packages with winget, changes Explorer, Start, search and theme settings, installs WSL with Ubuntu, and may restart your PC once. - Standard runs the bootstrap with -Action Partial. Full runs -Action Full and adds Developer Mode, Sudo, widgets off, two Edge policies and Remote Desktop. - The scripts verify Microsoft Authenticode signatures on everything they download, but irm | iex itself does not verify the small wrapper script. You can check it yourself first. - The uninstall script permanently deletes the Ubuntu distro without asking, and it removes the tools it manages even if you had them installed before. - Coreutils for Windows installs with winget install Microsoft.Coreutils. In PowerShell several commands clash with built-in aliases, which matters for scripts. The one-liners From the WindowsDeveloperConfig repo: # Standard experience irm https://aka.ms/devconfig/standard/setup.ps1 | iex # Full experience irm https://aka.ms/devconfig/full/setup.ps1 | iex # Uninstall (covers both) irm https://aka.ms/devconfig/standard/uninstall.ps1 | iex The aka.ms links redirect to setup-standard.ps1, setup-full.ps1 and uninstall.ps1 in the repo. Each wrapper is about 20 lines. It downloads bootstrap.ps1 from a pinned commit, checks that the signer is Microsoft Corporation, and only then runs it with -Action Partial, -Action Full or -Action Uninstall. The repo is honest about the gap: "irm | iex does not verify the wrapper's own signature; it trusts the HTTPS endpoint." If you want to check the entry script too, download it and look before you run anything: $f = "$env:TEMP\setup-standard.ps1" Invoke-WebRequest https://aka.ms/devconfig/standard/setup.ps1 -OutFile $f Get-AuthenticodeSignature $f | Format-List Status, SignerCertificate notepad $f It is short enough to read in a minute, and it is a good habit for any irm | iex install, not just this one. What gets installed The Standard setup installs these with winget: | Area | Packages | |---|---| | Shell and terminal | Windows Terminal, Intelligent Terminal, PowerShell 7, Oh My Posh | | Source control | Git, GitHub CLI | | Editors and AI | VS Code, GitHub Copilot CLI | | Runtimes | .NET SDK 10, Python 3.14 + uv, Node.js LTS + nvm for Windows | | Cloud | Azure CLI | | Utilities | Coreutils for Windows, Windows App CLI, PowerToys, Visual C++ Redistributable | It then sets PowerShell 7 as the default Terminal profile, installs Cascadia Code NF and Cascadia Mono NF for all users, adds a GitHub Copilot profile to the Terminal dropdown, and installs WSL plus Ubuntu with wsl --install -d Ubuntu --no-launch. Practical numbers from the docs: roughly 30 minutes on a clean machine, about 15 GB of free disk space, up to two UAC prompts, and Windows 11 only. Windows 10 is not supported. What it changes on your machine This is the part worth reading twice. Some highlights from the documented registry changes and the "Known limitations" table: - Explorer: file extensions and hidden files shown, full path in the title bar, Explorer opens to This PC, no recent or frequent items in Quick Access. - Start and search: no web results in search, no Start recommendations, no search highlights. - Notifications: Do Not Disturb is turned on globally, not just for quiet hours, until you turn it back off. - Theme: dark mode for apps and the system. - Long paths: LongPathsEnabled set to 1. - Node: both Node.js LTS and nvm for Windows get installed. The docs suggest uninstalling Node.js first if you want nvm to own the PATH entry. - Your PowerShell profile: an Oh My Posh block is added to $PROFILE. If the profile already has other initialization, setup leaves it alone and flags it. - Terminal settings: settings.json is round-tripped through JSON, so comments are lost. A settings.json.bak is written first. The Full setup adds more: - Developer Mode and Sudo (inline mode). - Widgets turned off through policy. - Two Edge settings written as policy, so Edge will say it is "managed by your organization". - Remote Desktop allowed (fDenyTSConnections set to 0). The docs note the firewall rule is not opened, but it is still a change to the machine's security posture. What it does not do, per the docs: no telemetry, no sign-ins, no credential changes, no Windows Defender changes. Git and the GitHub CLI are installed but not configured, so you still need git config user.name and gh auth login. There is also no dry run (-WhatIf) and no switch to skip individual packages. If you want a different package list, the documented path is to clone the repo, edit the files under src\windows-dev-config, and run the unsigned source with -AllowUnsigned. The restart and the uninstall WSL needs virtualization, so setup may restart the machine. It warns you and restarts after 10 seconds, so save your work before you start. A scheduled task called WindowsDevConfigResume picks the run up after you sign back in. If nothing happens: Get-ScheduledTask -TaskName WindowsDevConfigResume Re-running the original one-liner is safe. Steps that are already done report already OK and are skipped. Logs go to devconfig-log.txt under %ProgramData%\CalmOS. The uninstall deserves a warning of its own. According to the docs it: - Permanently deletes Ubuntu and its files, without confirmation. - Removes the tools it manages, including copies you had installed before running setup. - Resets settings to defaults rather than restoring what you had before (themes go back to light, for example). If you have real work inside that Ubuntu distro, export it first: wsl --export Ubuntu D:\backup\ubuntu.tar Coreutils for Windows Coreutils for Windows is a Microsoft-maintained build of the Rust uutils projects (coreutils, findutils and grep), shipped as one multi-call binary. It is MIT licensed and has x64 and ARM64 builds. The current release at the time of writing is v2026.9.3. The Standard setup installs it, or you can install it alone: winget install Microsoft.Coreutils Then the usual pipelines work in CMD and PowerShell: grep -rn "TODO" src | wc -l find . -name "*.log" -mtime +7 A few things we would want to know before relying on it in scripts: - PowerShell 7.4 or later is required, and 7.6 or later is recommended for ~ support. - Alias clashes. In PowerShell, cat, cp, ls, mv, pwd, rm, sleep, sort, tee and others share names with built-in aliases. The installer hooks into PSReadLine to rewrite what you type interactively, but it does not remove the aliases. Check what a name resolves to with Get-Command ls -All. - Some commands are not shipped because they clash with Windows built-ins or need POSIX features: dir, more, whoami, kill and timeout among them. chmod, chown and uname are dropped too. - No /dev/null. Use NUL, as in find . -name "*.log" > NUL. - CRLF line endings can still trip byte-oriented tools like uniq. - You can turn off individual utilities with coreutils-manager disable <utility name>. One detail that may confuse you: the Build blog calls Coreutils generally available, but the repo README still says "This project is in preview." Treat it like any young tool and test your scripts before switching a team over. Our take For a brand new machine or a throwaway VM, the Standard setup is a sensible default, and the signing and pinned-commit design is better than most irm | iex installers. On a machine you already use every day, we would read the settings list first, skip Full unless you actually want Remote Desktop and Edge policies, and back up WSL before you ever touch the uninstall script. Have you tried Windows Developer Config or Coreutils for Windows on a real machine yet? Did it save you time, or did it change something you had to undo? And would you trust a one-line setup script on your main dev box, or only on a fresh VM? We first wrote about the Build 2026 developer announcements on Windows Mode.
The error messages a Rust rewrite got subtly wrong: what a black-box probe found in uutils coreutils --- title: "The error messages a Rust rewrite got subtly wrong: what a black-box probe found in uutils coreutils" published: true tags: rust, cli, testing, opensource --- When you rewrite a command-line tool, the happy path is the easy part. Output for valid input gets compared early and often. Error messages are where rewrites quietly drift: a different wording, a missing file name, a raw (os error 20) instead of the sentence a script or a person expects. I have been running behave against uutils coreutils, the Rust rewrite of GNU coreutils. behave probes a CLI as a black box (flags from --help, stdin, files, odd inputs), records what the reference tool does, and replays the same cases against the rewrite. I record from GNU 9.12, the release uutils targets. One probe case added in v0.1.7 is simply "a regular file passed with a trailing slash" (f/). It turned out to be a good bug finder, because every utility has to turn ENOTDIR into a message, and each one does it a little differently. What it found All of these were reported upstream with a fix PR and a test: - cp f/ dest printed Not a directory (os error 20); GNU says cannot stat 'f/': Not a directory (#15691, #15692) - shred dir said Not a file; GNU says failed to open for writing: Is a directory (#15630, #15631) - mv missing/ g reported the wrong reason for the source (#15704, #15705) - ln f/ link blamed the link instead of the source (#15713, #15714) - mv a missing/b printed only the OS error, no cannot move 'a' to ... (#15721, #15722) - mv -T f d left the source out of cannot overwrite directory (#15724, #15725) - paste open and read errors without the file name (#15642) - sort -c dir exited 0 with no message at all (#15615, fixed in #15616, merged) And one that is not about messages: mv -n z z fails with 'z' and 'z' are the same file, while GNU skips the move and exits 0, because it never runs the same-file check when it would not replace the target anyway (#15824, #15825). Why these slip through None of these are hard to fix. Most patches are a few lines plus a test. They slip through because a rewrite's own test suite tends to assert what the authors thought of, and nobody thinks of cp f/ dest. A black-box recording of the original tool asserts everything it actually does, including the boring corners. Two lessons from the review rounds: 1. Match the reference release. GNU 9.7 and 9.12 differ in small ways (quoting in tail -v headers), so recording from an old GNU produces false positives. 2. Exact OS error text differs between platforms. Tests that compare full strerror text need to be Unix-only, while the context part (cannot move 'a' to 'b') can be checked everywhere. Try it brew install emirmrkaljevic/tap/behave # or: go install github.com/emirmrkaljevic/behave/cmd/behave@latest behave probe cp # record the reference (GNU cp) behave diff behave-cp --impl ./target/release/cp --skip-tag meta # replay against your rewrite If you are porting a CLI to Rust or Go, I would love to hear which cases behave misses.
uutils coreutils 又又又是 Rust 开发的 uutils/coreutils
I don’t remember the answer, but the real reason was of course cost. But now, for pennies, Claude will just…do that for you, in the typesafe language of your choice. There are whole efforts to do this (like uutils/coreutils), and they leverage coding agents!
Ubuntu 26.10 Finishes the Rust Coreutils Switch. What Should Developers Test? --- title: "Ubuntu 26.10 Finishes the Rust Coreutils Switch. What Should Developers Test?" published: true description: "Rust-based cp, mv and rm are only part of Ubuntu 26.10's compatibility story. A practical guide to testing OpenSSL 4, toolchains, CI and upgrade risks." tags: ubuntu, linux, devops, rust cover_image: dev-to-uploads.s3.us-east-2.amazonaws.com --- A deployment script can carry years of undocumented assumptions: a particular cp option, an error string parsed by a build step, or a crypto library loaded through an old interface. Most of the time, those assumptions stay invisible. Ubuntu 26.10 Stonking Stingray, released on October 15, 2026, gives developers a reason to look for them. Its default cp, mv, and rm now come from Rust-based uutils. It also ships OpenSSL 4, a refreshed language and compiler stack, ROCm 10, and a Linux 7.3-based kernel. There is a catch: 26.10 is an interim release, supported only through July 2027. That makes the decision different for a CI image, a personal workstation, and a production server. TL;DR: Ubuntu 26.10 is worth testing, not blindly adopting. Check GNU-versus-uutils behavior, OpenSSL 4 dependencies, and your actual build pipeline. Containers cover userspace regressions; kernel and driver changes need a VM or host. For long-lived production systems, 26.04 LTS remains the sensible default. Here is the checklist I would use before changing a real workload. The commands are reproducible suggestions, not results from a benchmark I ran. First, understand what changed in cp, mv, and rm Ubuntu had already moved many command-line utilities to uutils in earlier releases. The three remaining GNU holdouts — cp, mv, and rm — stayed on GNU in 26.04 LTS because of unresolved compatibility concerns. Canonical says the migration is complete in 26.10. The language behind a command is usually irrelevant to a shell script. Its observable behavior is not. Consider the things scripts routinely depend on: - accepted flags and option combinations; - exit statuses, especially under set -e; - the precise output of --version and error messages; - symbolic links, permissions, ownership, and cross-filesystem moves; - behavior on unusual filenames or non-UTF-8 input. The uutils project aims to be GNU-compatible. It does not claim every GNU edge case is already identical. An upstream compatibility tracker still lists options such as cp --keep-directory-symlink and mv --no-copy as missing in its September comparison. That is a reason to inspect the packaged version you actually run, not evidence that every installation of 26.10 currently fails those cases. An independent DevOps Daily comparison tested 162 command cases in an Ubuntu 26.10 beta environment and reported 150 byte-identical captured results and 12 differences. The differences included version identification, Unicode handling, exit codes, partial decoding, and diagnostic wording. Those are their measurements, not mine; 162 selected cases do not measure the entire compatibility surface. A ten-minute smoke test that stays inside a temp directory Start with identity. This is safe to run on the system you intend to test: cat /etc/os-release | grep -E '^(NAME|VERSION|VERSION_ID)=' for tool in cp mv rm; do printf '%s: ' "$tool" "$tool" --version | head -n 1 done If Ubuntu's prefixed GNU tools are available, the following probe checks option visibility without replacing system binaries. The script prints observations, not predetermined pass/fail claims: for pair in 'cp --keep-directory-symlink' 'mv --no-copy'; do read -r tool option <<< "$pair" for bin in "$tool" "gnu$tool"; do if ! command -v "$bin" >/dev/null 2>&1; then printf '%s: not installed\n' "$bin" elif "$bin" --help 2>&1 | grep -Fq -- "$option"; then printf '%s: %s listed\n' "$bin" "$option" else printf '%s: %s NOT listed\n' "$bin" "$option" fi done done --help is only an initial check. It cannot establish that an option has correct semantics. Follow it with fixtures from your actual build and deployment workflows. For a small, non-destructive filesystem comparison, run this in a disposable Ubuntu 26.10 VM or container where gnucp and gnumv are available: #!/usr/bin/env bash set -euo pipefail for bin in cp mv gnucp gnumv; do command -v "$bin" >/dev/null || { echo "Missing $bin; cannot compare implementations" >&2 exit 2 } done work="$(mktemp -d)" trap 'rm -rf -- "$work"' EXIT mkdir -p "$work/input/sub" printf 'alpha\n' > "$work/input/a.txt" printf 'beta\n' > "$work/input/sub/b.txt" for implementation in uutils gnu; do prefix='' [[ "$implementation" == gnu ]] && prefix='gnu' mkdir -p "$work/$implementation" "${prefix}cp" -R \ "$work/input" \ "$work/$implementation/copied" "${prefix}mv" \ "$work/$implementation/copied/a.txt" \ "$work/$implementation/moved.txt" ( cd "$work/$implementation" find . -type f -exec sha256sum {} + | LC_ALL=C sort ) > "$work/$implementation.manifest" done diff -u \ "$work/uutils.manifest" \ "$work/gnu.manifest" A zero exit code means this tiny fixture produced matching file paths and content hashes. It says nothing about ACLs, extended attributes, sparse files, symlink semantics, timestamps, ownership, or error handling. Add those deliberately when your application requires them. You can also capture stdout, stderr, exit codes, and the resulting tree for each case. One more practical point: a --version check that searches for the string GNU can silently select the wrong branch in a legacy script. Search your repositories for these probes before an upgrade. !A technical map of Ubuntu 26.10 compatibility checks across shell commands, crypto, language runtimes, kernel and GPU software. Figure 1. A testing map compiled from Canonical's release notes; it does not represent benchmark results. OpenSSL 4 may be the harder migration The Rust switch attracts attention because everyone recognizes cp. OpenSSL 4 deserves at least as much attention if you maintain native software, hardware-security-module integrations, or older TLS infrastructure. OpenSSL 4 removed the ENGINE API. Ubuntu's 26.10 notes specifically explain that PKCS#11-engine configurations must move to the PKCS#11 provider model. OpenSSL 4 also removes older interfaces and legacy protocol behavior. These changes are relevant even if your own application never calls the openssl executable directly. Useful read-only inspection commands are: openssl version -a openssl list -providers Then inspect the OpenSSL configuration used by your application for references to engine_id, dynamic_path, and pkcs11. Redact secrets before sharing logs. Rebuild native dependencies against the target headers, and test a real TLS handshake or HSM operation. openssl version alone cannot prove application compatibility. For older systems, this is a more specific question than “Does it support OpenSSL 4?”: Is a provider available for the key material and algorithms the application actually uses? Newer toolchains: choose tests that match the dependency Canonical lists the following in its Ubuntu 26.10 release notes: | Component | Listed version | A useful regression check | | --- | --- | --- | | Python | 3.14.7 | Build a fresh environment, install native wheels, and run the suite | | Go | 1.27 | go test ./..., go vet ./..., code generation, cross-builds | | LLVM | 22.1.8 | Rebuild LLVM plugins, generated IR, sanitizers, native extensions | | .NET | 10.0.112 | Check dotnet --info, restore, build, test, publish, native dependencies | | ROCm | 10.0 | Check supported GPUs, rebuild AMD SMI users, run actual GPU workloads | | Kernel | 7.3-based | Test drivers, DKMS, eBPF, virtualization and filesystem behavior | The version numbers are those listed in the release notes, not a claim about the latest patch currently installed on every updated machine. ROCm has a particularly concrete breaking boundary: Canonical documents an AMD SMI SONAME change to libamd_smi.so.27, removed deprecated AMD SMI APIs, and removal of rocsparse_indextype_u16. Software that links to the changed library needs rebuilding. For GPU work, verify the exact device against the supported hardware list before planning a migration. The Ubuntu release image also uses a 7.3.0-9.9 kernel built from upstream 7.3-rc6. The upstream 7.3 final release arrived after Ubuntu 26.10's release date. To troubleshoot a driver issue, record uname -r and the installed Ubuntu package rather than just writing “Linux 7.3”. A container is not a kernel test You can use a 26.10 container to detect userspace regressions, for example: docker run --rm ubuntu:26.10 bash -lc \ 'cat /etc/os-release | grep VERSION=; cp --version | head -1' Verify image availability and pin a digest for repeatable CI. But the container shares its host kernel. uname -r inside that container reports the host kernel, not a separately installed Ubuntu 26.10 kernel. Kernel modules, DKMS, real device drivers, and most GPU integration problems need a VM or physical test host. That distinction matters when someone says an upgrade passed “in Docker.” It may have passed only the userspace portion. There are desktop and operational changes too Ubuntu 26.10 uses GNOME 51. It also offers Myna, an optional, not-preinstalled local speech-to-text technology preview: transcription runs on the device rather than sending audio to a network service. These may matter to workstation users, but neither answers whether a production build is ready to move. Canonical documents both. On servers, inspect SSH authentication before touching a remote box. In 26.10, GSSAPI/Kerberos-capable OpenSSH packages are split into the openssh-gssapi family; the ordinary client/server packages do not provide that feature. If access depends on it, stage and test that exact access path first. Canonical also says upgrades from 26.04 LTS with TPM-backed full-disk encryption were not supported at the initial 26.10 release. Consult the current known-issues section before any encrypted-system upgrade, because restrictions may be updated during the release lifecycle. My upgrade decision would depend on the workload !A decision guide showing Ubuntu 26.04 LTS as a production baseline and Ubuntu 26.10 as a parallel test lane before a staged rollout. Figure 2. A recommended rollout sequence, not an Ubuntu policy or a guarantee of compatibility. For a developer laptop, 26.10 is attractive if your hardware and dependencies need the new stack and you are comfortable with a nine-month support window. Save a recovery path first. For CI, add 26.10 in parallel with the existing image. Compare builds, packages, automated tests, and shell scripts. Use a container job for userspace; use a VM or host runner when kernel behavior is part of the test. Do not assume ubuntu-26.10 is a valid GitHub-hosted Actions runner label just because an Ubuntu version exists. For a production server, my default would remain 26.04 LTS unless there is a specific capability worth the maintenance and migration cost. Check crypto configuration, SSH/Kerberos, drivers, and a tested rollback path before rollout. An interim release is a poor substitute for a support-lifecycle decision. The checklist I'd save before upgrading - Shell compatibility: Inventory the exact command implementations and GNU-only options your scripts use. - Behavioral testing: Run real shell fixtures under GNU and uutils. Compare side effects, not just output. - Automation: Find scripts that parse version strings, diagnostic messages, or exit codes. - OpenSSL 4: Rebuild native integrations and migrate ENGINE-based PKCS#11 configurations. - Toolchains: Install Python dependencies from scratch. Build and test .NET, Go, and LLVM projects where applicable. - GPU workloads: Validate ROCm against supported hardware and rebuild affected AMD SMI consumers. - Kernel compatibility: Test drivers, DKMS, and other kernel-dependent features outside containers. - System access: Verify Kerberos/GSSAPI authentication and TPM-backed encryption upgrade constraints. - Rollback readiness: Confirm the nine-month support window and rehearse a recovery procedure. My practical takeaway is to add Ubuntu 26.10 to the compatibility matrix before making it a default. Even if you plan to stay on LTS, this release is a useful early warning for assumptions buried in tooling and deployment scripts. Have you seen a real GNU-versus-uutils incompatibility in a build or deployment? A small reproducible case — exact command, package version, expected and observed behavior — would make a far more useful comment than a generic upgrade verdict. References - Canonical — Ubuntu 26.10 release announcement - Ubuntu 26.10 release notes (features, breaking changes, known issues) - uutils coreutils project - uutils GNU-compatibility issue tracker - DevOps Daily's independent 162-case test on 26.10 beta - OpenSSL 4.0 removed APIs - OpenSSL migration guide Technical scope: release documentation and community test evidence reviewed October 21, 2026. The shell examples are provided for readers to execute and verify on their own systems; no first-party Ubuntu 26.10 benchmark is claimed in this article.
tail: cannot open '7': when localisation reformats your file names --- title: "tail: cannot open '7': when localisation reformats your file names" published: true tags: rust, i18n, testing, cli --- Ask uutils tail (the Rust rewrite of GNU coreutils) for a file that doesn't exist and it tells you so. Unless the file is called 007: $ tail 007 # GNU coreutils 9.12 tail: cannot open '007' for reading: No such file or directory $ tail 007 # uutils main tail: cannot open '7' for reading: No such file or directory 1e3 comes back as 1000, 1.50 as 1.5, +5 as 5. Try tail 1e3 on a directory and you get "error reading '1000'". Where the 7 comes from uutils translates its messages with Fluent. Every argument goes through a translate! macro, and that macro checks whether the value parses as a number. If it does, it hands Fluent a number instead of a string, so the locale can format it (digit grouping, decimal separator). That's what you want for "3 files failed". It's not what you want for a file name that just happens to look like a number: Fluent prints the number, not the text you typed. The project already has translate_text! for exactly this, and date and the sort --check "disorder" line were fixed the same way earlier. The tail fix (#15534, merged a few hours after I opened it) switches the call sites that take a file name, tac (#15541) was merged the same day, and nl (#15544) and the shared checksum code behind md5sum/cksum (#15548) were merged the next morning. The same pattern still shows up in dd, sort, shred and in clap's "unexpected argument" error, all listed in #15533. The general lesson, if you localise a CLI with Fluent or ICU MessageFormat: anything the user typed (paths, operands, input lines) should go in as a string. Let only real counts be numbers. Catching it automatically I found this with behave, which probes a command as a black box, records what the original does and replays it against a rewrite. Its generated cases always included "missing file", but with the name does-not-exist.txt, which no number parser will touch. Since v0.1.6 behave probe also adds a missing-file case with the names 007 and 1e3: ✗ missing file named like a number 0008-missing-file-named-like-a-number.yaml $ tail 007 1e3 stderr: - $CMD: cannot open '007' for reading: No such file or directory - $CMD: cannot open '1e3' for reading: No such file or directory + $CMD: cannot open '7' for reading: No such file or directory + $CMD: cannot open '1000' for reading: No such file or directory It costs one case per tool and checks something every port that translates its messages can get wrong. go install github.com/emirmrkaljevic/behave/cmd/behave`latest # or: brew install emirmrkaljevic/tap/behave behave probe tail --out spec-tail behave diff spec-tail --impl ./target/release/tail --- behave is open source (MIT): emirmrkaljevic/behave · more from me on GitHub
@mateusza @ubuntu One more improvement: coreutils#15418