How to remove system locales, as oppose to package locales as asked in How to remove unnecessary locales??

I'm getting the following errors recently:

locale: Cannot set LC_ALL to default locale: No such file or directory

The only en locale I have in my system:

$ grep -r en /var/lib/locales/supported.d/*
/var/lib/locales/supported.d/local: en_US ISO-8859-1
/var/lib/locales/supported.d/local: en_US.UTF-8 UTF-8

$ locale -a | grep en
en_US
en_US.iso88591
en_US.utf8

but not en, as complained by perl:

perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
        LANGUAGE = "",
        LC_ALL = (unset),
        LC_MEASUREMENT = "en",
        LC_PAPER = "en",
        LC_MONETARY = "en",
        LC_NAME = "en",
        LC_ADDRESS = "en",
        LC_NUMERIC = "en",
        LC_TELEPHONE = "en",
        LC_IDENTIFICATION = "en",
        LC_TIME = "en",
        LANG = "C"

So I add the locale en by:

% locale-gen en
Generating locales (this might take a while)...
  en_AG.UTF-8... done
  en_AU.UTF-8... done
  en_BW.UTF-8... done
  en_CA.UTF-8... done
  en_DK.UTF-8...^C

I don't want any of above locales (only en_US), but now I can't get rid of them -- I followed the steps in https://serverfault.com/questions/394610/remove-a-locale-in-ubuntu

But when it comes to the last step, I'm still getting:

% locale-gen
Generating locales (this might take a while)...
  en_AG.UTF-8... done
  en_AU.UTF-8... done
  en_BW.UTF-8... done
  en_CA.UTF-8... done
  en_DK.UTF-8...^C

How to remove all above locales and keep only en_US?

Conclusion & Supplement

Thanks to Gunnar's answer, it is indeed caused by entries in /etc/locale.gen, for those extra locales. Just FTR, this is what locale-gen en has changed in /etc/locale.gen:

$ sed '/^#/d; /en/p;' /etc/locale.gen


en_AG UTF-8
en_AG UTF-8
en_AU.UTF-8 UTF-8
en_AU.UTF-8 UTF-8
en_BW.UTF-8 UTF-8
en_BW.UTF-8 UTF-8
en_CA.UTF-8 UTF-8
en_CA.UTF-8 UTF-8
en_DK.UTF-8 UTF-8
en_DK.UTF-8 UTF-8
en_GB.UTF-8 UTF-8
en_GB.UTF-8 UTF-8
en_HK.UTF-8 UTF-8
en_HK.UTF-8 UTF-8
en_IE.UTF-8 UTF-8
en_IE.UTF-8 UTF-8
en_IL UTF-8
en_IL UTF-8
en_IN UTF-8
en_IN UTF-8
en_NG UTF-8
en_NG UTF-8
en_NZ.UTF-8 UTF-8
en_NZ.UTF-8 UTF-8
en_PH.UTF-8 UTF-8
en_PH.UTF-8 UTF-8
en_SC.UTF-8 UTF-8
en_SC.UTF-8 UTF-8
en_SG.UTF-8 UTF-8
en_SG.UTF-8 UTF-8
en_US.UTF-8 UTF-8
en_US.UTF-8 UTF-8
en_ZA.UTF-8 UTF-8
en_ZA.UTF-8 UTF-8
en_ZM UTF-8
en_ZM UTF-8
en_ZW.UTF-8 UTF-8
en_ZW.UTF-8 UTF-8

As a comparison, here is what the default looks like (i.e., without any of the above extra locales):

$ sed '/^#/d;' /etc/locale.gen; echo ---


---

You should edit /etc/locale.gen and comment the locales you don't want. Then run

sudo locale-gen

There does not exist any locale with the name en. The one you probably want to use is en_US.UTF-8 and not en_US. (The latter enables latin1 encoding.)


Note: Some of the commands below require root privileges, consider the use of sudo.

Basic info

According to man locale-gen, locales are set in several files.

/etc/locale.gen

The main configuration file, which has a simple format: every line that is not empty and does not begin with a # is treated as a locale definition that is to be built.

/var/lib/locales/supported.d/

A directory containing locale.gen snippets provided by language-pack packages. Do not edit these manually, they will be overwritten on package upgrades.

Comprehensive details on locales at the Arch Wiki.

Checking locales and the locale

To check the (already) generated locales, run any of the following commands (with minor output differences).

locale -a
localedef --list-archive
localectl list-locales

To check the currently used locale, run any of the following commands (with minor output differences).

locale
localectl

Setting and generating (new) locales

Locales are typically set by uncommenting lines in /etc/locale.gen, after which running locale-gen is required.

nano /etc/locale.gen # uncomment desired lines (locales)
locale-gen

This will generate locales files for each uncommented line in /etc/locale.gen (and under /var/lib/locales/supported.d/), whether they were previously generated or not.

Alternatively, the command

locale-gen <locale>

will uncomment the corresponding line in locale-gen while generating the desired locale and only this one.

Removing locales

To remove locales in /etc/locale.gen, simply comment the desired lines and regenerate the locales using locale-gen. The command locale-gen --purge <locale> doesn't do what the modifier suggests.

To remove locales under /var/lib/locales/supported.d/ is trickier. Since any file /var/lib/locales/supported.d/<code> depends on the package language-pack-<code>-base, any change on the former will be restored when the latter is updated.

Workaround. To prevent changes under /var/lib/locales/supported.d/, set files in it with the "immutable (i)" attribute. So instead of removing files, empty them. For instance:

cd /var/lib/locales/supported.d/
rm <code> && touch <code> # <code> has been emptied
lsattr <code>    # regular attributes
chattr +i <code> # adding (+) immutable
lsattr <code>    # checking attributes

Setting the locale

Setting and generating locales does not set the system locale. Any of the following commands achieves this.

echo LANG=<code> | sudo tee /etc/locale.conf # reboot (might be ignored in Ubuntu)
localectl set-locale LANG=<code>