dotdee(8)
π dotdee(8) β bestie's guide to the dynamic-file generator π
okay so this is dotdee, and it lives in section 8 of the manual (that's the sysadmin zone, very main character energy π). Buckle up, this one's actually so good.
β¨ NAME β¨
dotdee β converts a flat file into one that's dynamically generated from a .d directory. That's the whole serve. π«Ά
π SYNOPSIS π
Pick your mode, bestie. One at a time. No mixing. π
dotdee -c|--comment /PATH/TO/FILE [COMMENT_DELIMITER_START [COMMENT_DELIMITER_END]]
dotdee -d|--dir /PATH/TO/FILE
dotdee -l|--list
dotdee -o|--original /PATH/TO/FILE
dotdee -s|--setup /PATH/TO/FILE [COMMENT_DELIMITER_START [COMMENT_DELIMITER_END]]
dotdee -u|--update /PATH/TO/FILE
dotdee --update-contents /PATH/TO/FILE
dotdee --update-link /PATH/TO/FILE
dotdee --undo /PATH/TO/FILE
And for the people who need the receipts, here's what each one is shaped like:
-c,--commentβ takes/PATH/TO/FILE, plus optionallyCOMMENT_DELIMITER_STARTandCOMMENT_DELIMITER_ENDπ-d,--dirβ takes/PATH/TO/FILE-l,--listβ takes literally nothing, it just vibes π¦-o,--originalβ takes/PATH/TO/FILE-s,--setupβ takes/PATH/TO/FILE, plus optionallyCOMMENT_DELIMITER_STARTandCOMMENT_DELIMITER_END-u,--updateβ takes/PATH/TO/FILE--update-contentsβ takes/PATH/TO/FILE--update-linkβ takes/PATH/TO/FILE--undoβ takes/PATH/TO/FILE
πΈ DESCRIPTION πΈ
okay so <purple>dotdee</purple> is an administrative utility β it's the one you call when you want to convert a flatfile into a dynamically generated file, from a .d directory. Iconic behaviour, honestly.
Here's the glow-up it performs: the original path at /PATH/TO/FILE gets replaced with a symbolic link pointing at /etc/dotdee/PATH/TO/FILE, and that file is dynamically generated by concatenating all of the files in /etc/dotdee/PATH/TO/FILE.d/*, per the order of the shell. Chef's kiss. π
And the magic that keeps it fresh? The Linux kernel's inotify(7) mechanism, which <cyan>dotdee</cyan> uses by running iwatch(1) against the /etc/dotdee/ directory. Any changes to the constituent files are automatically reflected in the constructed, dynamically generated file. So β and this is the part that matters β as long as iwatch(1) is running, you should never need to actually run dotdee --update /PATH/TO/FILE manually. Not me telling you twice. π«Ά
π what lives in the .d directory π
There is at least 1 file always present in an /etc/dotdee/PATH/TO/FILE.d/ directory:
50-originalis the original file being managed; note that write permissions are removed from this file, as we don't want to ever modify it. Hands off, bestie. π
Optionally, a 2nd file might be present in an /etc/dotdee/PATH/TO/FILE.d/ directory:
.commentis a text file that defines the "comment" string; if, for instance, the contents of.commentis the#character, the following will be printed to the head of the generated file:
# DO NOT EDIT THIS FILE DIRECTLY!
# Rather, add, remove, or modify file(s) in [/etc/dotdee/path/to/some.conf.d]
# per the dotdee(8) manpage.
Alternatively, .comment might contain //, or ;, or anything else that denotes that the rest of the string will be a comment. It's flexible like that. π
As for the rest of the contents of the /etc/dotdee/PATH/TO/FILE.d/ directory β all of them must begin with 2 or more digits, to ensure that they are processed in a specific order. The numbers are the whole point, don't skip them. π₯
β the 3 supported file types β
- plain text files, which must not be executable; these files are simply concatenated in order
- executable files; these files are executed, with the current state of the managed file provided on
STDIN, and theSTDOUTis then written to the managed file - patch/diff files; these files end in either
.patchor.diff, and are applied using thepatch(1)command to the current state of the managed file
π₯ EXAMPLES π₯
This is the part where it all clicks, bestie. Watch. π
π¦ step 1: set it up
$ sudo dotdee --setup /etc/hosts
update-alternatives: using /etc/dotdee/etc/hosts to provide /etc/hosts (etc:hosts) in auto mode.
π¦ step 2: look at the link chain, it's giving nesting dolls
$ ll /etc/hosts
lrwxrwxrwx 1 root root 27 2011-05-25 00:26 /etc/hosts -> /etc/alternatives/etc:hosts
$ ll /etc/alternatives/etc:hosts
lrwxrwxrwx 1 root root 22 2011-05-25 00:26 /etc/alternatives/etc:hosts -> /etc/dotdee/etc/hosts
$ ll /etc/dotdee/etc/hosts
-rw-r--r-- 1 root root 221 2011-05-16 01:40 /etc/dotdee/etc/hosts
π¦ step 3: the original contents
$ cat /etc/hosts
127.0.0.1 localhost
# The following lines are desirable for IPv6 capable hosts
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
ff02::3 ip6-allhosts
π¦ step 4: drop a new numbered file in and watch the magic
$ echo 10.9.8.7 somehost | sudo tee /etc/dotdee/etc/hosts.d/10-somehost
$ cat /etc/hosts
10.9.8.7 somehost
127.0.0.1 localhost
# The following lines are desirable for IPv6 capable hosts
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
ff02::3 ip6-allhosts
π¦ step 5: patches, because why edit when you can diff
$ cat /etc/dotdee/etc/hosts.d/60-googledns.patch
--- /etc/hosts 2011-05-16 01:40:03.000000000 +0000
+++ /tmp/hosts.new 2011-05-25 00:30:41.187412417 +0000
@@ -1,6 +1,8 @@
10.9.8.7 somehost
127.0.0.1 localhost
+8.8.8.8 googledns
+
# The following lines are desirable for IPv6 capable hosts
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
$ cat /etc/hosts
10.9.8.7 somehost
127.0.0.1 localhost
8.8.8.8 googledns
# The following lines are desirable for IPv6 capable hosts
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
ff02::3 ip6-allhosts
π¦ step 6: executable files get STDIN, give STDOUT
$ cat /etc/dotdee/etc/hosts.d/90-uppercase
#!/bin/sh
tr '[:lower:]' '[:upper:]'
$ cat /etc/hosts
10.9.8.7 SOMEHOST
127.0.0.1 LOCALHOST
8.8.8.8 GOOGLEDNS
# THE FOLLOWING LINES ARE DESIRABLE FOR IPV6 CAPABLE HOSTS
::1 IP6-LOCALHOST IP6-LOOPBACK
FE00::0 IP6-LOCALNET
FF00::0 IP6-MCASTPREFIX
FF02::1 IP6-ALLNODES
FF02::2 IP6-ALLROUTERS
FF02::3 IP6-ALLHOSTS
π¦ step 7: finding your way around
$ sudo dotdee --dir /etc/hosts
/etc/dotdee/etc/hosts.d
$ cat /some/hosts/snippet > $(sudo dotdee --dir /etc/hosts)/60-foo
$ sudo dotdee --original /etc/hosts
/etc/dotdee/etc/hosts.d/50-original
$ cat /some/other/hosts/file > $(sudo dotdee --original /etc/hosts)
π¦ step 8: custom comment delimiters, for the XML girlies
$ sudo dotdee --comment /path/to/some.xml '<!--' '-->'
π SEE ALSO π
update-alternatives(8), iwatch(1), patch(1) β go read those too, they're part of the lore. π
π AUTHOR π
This manpage and the utility was written by Dustin Kirkland <kirkland@ubuntu.com> for Ubuntu systems (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 3 published by the Free Software Foundation.
On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL, or on the web at http://www.gnu.org/licenses/gpl.txt.
and that's the whole page, bestie π this dotdee(8) manual dropped on 21 May 2011 and it's still serving looks. periodt. π
β¨
π¦ where this page comes from
- ubuntu jammy: dotdee 2.0-0ubuntu2 Β· GPL-3.0-only
- ubuntu noble: dotdee 2.0-0ubuntu2 Β· GPL-3.0-only
- ubuntu resolute: dotdee 2.0-0ubuntu3 Β· GPL-3.0-only
- ubuntu stonking: dotdee 2.0-0ubuntu3 Β· GPL-3.0-only
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms