For one user account, I want to have some bash scripts, which of course would be under version control.
The obvious solution is just to put the scripts in a git repository and make ~/bin a symlink to the scripts directory.
Now, it seems on systemd systems ~/.local/bin is supposedly the directory for user scripts.
My question, is mostly, what are the tradeoffs between using ~/bin and ~/.local/bin as directory for my own bash scripts?
One simple scenario I can come up with are 3rd party programs which might modify ~/.local/bin and put their own scripts/starters there, similar to 3rd party applications which put their *.desktop files in ~/.local/applications.
Any advice on this? Is ~/.local/bin safe to use for my scripts or should I stick to the classic ~/bin? Anyone has a better convention?
(Btw.: I am running Debian everywhere, so I do not worry about portability to non systemd Linux systems.)
Solved: Thanks a lot for all the feedback and answering my questions! I’ll settle with having my bash scripts somewhere under ~/my_git_monorepo and linking them to ~/.local/bin to stick to the XDG standard.
I use
~/.local/binsince by linux standard,~/.localis a user-level/usr/local, which is a override level of/usr~/binends up cluttering the home folderAnother reason to use
~/.localis you can do things like./configure --prefix=$HOME/.local make -j$(ncpu) make installAnd then you get your
.local/bin,.local/share,.local/include,.local/liband such, just like/usrbut scoped to your user.and it should mostly just work as well.
And if there’s other users in the machine, it doesn’t fuck things up for others Or if it ends up messing something up, it is user-scoped, so its a lot easier to fix than a bricked system
Another follow up question: Is there any documentation for the linux standard/convention of ~/.local/bin? My initial search about this resulted in nothing which I would call authoritative/definitive.
freedesktop.org defines environment variables that should be used by applications to store their stuff;
[archlinux.org] has a (non-authoritative) summary, but it also provides a [link to the actual specification].Thank you so much, bookmarked all of your links! :-)
If I hand write bash scripts, or for those single binary downloads, they’ll go into ~/bin. ~/.local is already used by a ton of packages. This helps a ton when it comes to backups or for just finding where I put stuff.
My ~/.local is
283 GB, it’s where podman/docker/etc put containers, it may as well be a system managed folder at that point. My ~/bin is only120 MBand is a lot simpler to backup/restore/sync to other desktops.At that point I’d poke around what’s in there, cuz there’s absolutely a mess in there
It’s really not. Python virtualenv, Steam, libvirt, composer, krita, vulkan, zed, zoxide, systemd, etc. ~/.local is the domain of various installed packages, not my hand crafted scripts.
Neither ~/bin or ~/.local/bin are part of most shell’s default
$PATHso you’re going to have to modify the user’s shell profile (or rc) to include it. It’s possible that your favorite distro includes it but not mine. For example(s): unset PATH /bin/bash --noprofile --norc bash-5.2$ echo $PATH /usr/local/bin:/usr/binor
unset PATH /bin/zsh --no-rcs --no-global-rcs Sinthesis% echo $PATH /bin:/usr/bin:/usr/ucb:/usr/local/bin ls -l /bin lrwxrwxrwx. 1 root root 7 Jan 23 2024 /bin -> usr/binThat was on Fedora. The funny thing is /bin is soft linked to usr/bin, weeeee.
This is on Debian
Sinthesis@debian:~$ /bin/bash --noprofile --norc bash-5.2$ echo $PATH /usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:.I’m not sure why you’re bringing the XDG or systemd “standard” into this. POSIX standard would be more appropriate but they don’t say anything on the matter, nor should they really. The most important thing is, be predictable. If the user has a problem with one of your scripts, what do they do first?
which wolf_binwill show them the full path to the script. So really, the location does not matter much.That said I would go with one of these two options:
-
Make a package for your distro. This may be overkill for a couple scripts but you did say they’re in a git repository so you could automate it. The package would install to /usr/bin which would require sudo or root. If the scripts are only allowed to be run by one user, set the rwx and group permissions.
-
A pattern I like, especially for lightweight things such as scripts that don’t require compiling or OS management and also are using git; a “hidden” or “dot” directory in the user’s home where the repo lives e.g.
~/.lemmywolf/Then add scripts directory to the user’s $PATH e.g.PATH=$PATH:~/.lemmywolf/scripts. This is what some fairly large projects like pyenv or volta do. You could take it a step farther and modify this installer script to your liking https://github.com/pyenv/pyenv-installer/blob/master/bin/pyenv-installer
/edit 20 year Linux user (Redhat AS2.1) and 5 years of Unix (HPUX & Solaris) before that.
/edit2 I just noticed the pyenv-installer does not modify the user’s shell profile. That could easily be added to the script though.
-
Put them wherever you want, don’t let Poettering dictate what you do with YOUR system. It is better NOT to put them in system directories since those will get overwritten by upgrades.
It is better NOT to put them in system directories since those will get overwritten by upgrades.
That’s a purely Atomic thing, isn’t it?
thats fair, but that shouldn’t make you avoid sensible freedesktop dirs just out of spite.
Local python uses ~/.local/bin, so in the interest of avoiding conflict, it is probably better to use ~/bin.
i have ~/bin as a syncthing folder because i manage several machines and if i update a script on one machine i want that synced to all of them. Then i just use . local for stuff that doesnt need syncing.
Since both locations are under
$HOMEthe singular difference between them is the hidden aspect of~/.local. That’s pretty much it.I migrated to fish recently and at first I was really annoyed that I had to decompose my
~/.bash_aliasesinto 67 different script files inside~/.config/fish/functions/, but (a) I was really impressed with the tools that fish gave me to quickly craft those script files (-~> function serg sed -i -e "s/$1/$2/g" $(rg -l "$1") end ~> funcsave serg funcsave: wrote ~/.config/fish/functions/serg.fish) - and (b) I realized it was something I ought to have done a while ago anyway.
Anyway, all this to say that fish ships with a lot of cool, sensible & interesting features, and one of those features is a built-in place for where your user scripts should live. (Mine is a symlink to
~/Dropbox/config/fish_functionsso that I don’t need to migrate them across computers).I really like fish. It’s just so pragmatic, I don’t know how to describe it differently. No groundbreaking concepts (like nu or elvish), but the tools you need are right there and easily accessible with syntax that doesn’t make me scratch my head (bash).
Personally I put scripts in
~/.local/bin/scripts/instead of just~/.local/bin/because I like to keep them separate from other binaries. To note: even though~/.local/bin/is in PATH, it’s subfolders are not, so if you do that you need to add thescriptssubfolder to PATH if you want to run the scripts directly.Well actually my scripts are in
mydotfilesrepo/home/.local/bin/scripts, and I use GNU Stow to symlinkmydotfilesrepo/hometo/home/myuser/(same formydotfilesrepo/etc/andmydotfilesrepo/usr/which are symlinked to/etcand/usr), but it’s the same result. Stow is pretty cool for centralizing your configs and scripts in one repo !I’ve never seen
~/binbefore so I can’t comment on whether it’s a good idea.I dislike having top-level directories in $HOME that aren’t storing media or documents. Some linux ports of games are awful for littering your homedir or Documents. Just lazy devs. Put it all in ~/.local please folks!
Oh yeah it’s so annoying when apps do that and put data in
.mozilla,.vscode, and.whateversin the home folder instead of following the specs and splitting it between.config,.local/shareand so on… I have 31.somethingin my home folder that shouldn’t be there and It’s a cluttered mess. And a few games not even bothering to start the folder names with a dot… 😡I’ll play the game for a while but if they litter my homedir then they are first on the chopping block when I’m looking to uninstall things and free up space.
Personally, I put a ~/.get-going or whatever you want to call it and put all my scripts in there. Name them with numbers first like “10-first.sh” “20-second.sh” and then just put a line in .bashrc or .zshrc or whatever you like. Aliases and any critical stuff last. Then one line in your rc file can include them all.
I made some bash scripts for distro-hopping that are now [undiscloded] years old so I can basically backup a few folders — the second being ~/bin where I put AppImages and stuff and sometimes ~/Development (I don’t always need the dev one because backups of those exist as repos) folder if I need to reinstall. A lot of people backup their whole home directory. But I prefer my method and that’s why we use Linux. I don’t want my settings for every app coming with me when I go on a new journey. Choose your own adventure.
Thanks, I think I get the idea, I just don’t understand the number-prefix, why did you start this convention?
(Btw.: For some years now I stick to the convention, that everything import is under one sub directory under my home. As long as I have a tarball backup of that sub directory, I am good to lose the whole hard disk w/o fear (e.g. ready for a clean upgrade, distro hop or just go traveling w/o fearing that I forgot to switch off the oven ;-)).
It’s just alphabetical so the scripts run in the right order. The numbers serve like “A” or “B” except you can add new scripts between one and ten if it comes up and your “10-whatever” file is a mess. It’s sort of a convention on Linux but not everyone does it.
Then you just add
for FILE in ~/.shellrc.d/*; do source $FILE doneTo your ~./bashrc (or your preferred shell). Replace shellrc.d with whatever you choose. I use shellrc.d on servers and stuff because the dot d is also kind of a convention for naming folders. People have their own opinions about that but don’t worry about it until you have strong opinions.
It just makes it easier to backup your customizations. I copy a lot of my settings in there. I use Vim (which isn’t necessarily the best choice but I’m old) so I just put my .vimrc stuff in my folder. Then you just have to backup one folder and, if nothing else, your CLI will stay the same.
People argue over emacs and vim (as text editors) and systemd vs init but it’s your machine. That’s part of what makes Linux fun.






