2

I have ~/bin folder that contains multiple subfolders with arbitrary directory levels.

This folder only for executable files that need to be added to path when start zsh, how to recursively add all files under its folder and its subfolders to $path in a short and effective way?

Tuyen Pham
  • 1,765
  • 1
  • 16
  • 46
  • 1
    [This might be helpful](https://unix.stackexchange.com/questions/17715/how-can-i-set-all-subdirectories-of-a-directory-into-path) – BarathVutukuri Nov 09 '18 at 16:31
  • 1
    I'm always curious when people ask for short or one-liner solutions. Are you in a situation that is scarce on bytes? Is readability/maintainability a concern at all? – Jeff Schaller Nov 09 '18 at 16:34
  • Thanks @BarathVutukuri, what if we use `fd` instead of `find`?. @Jeff: for a neat config file, minimal config that fit all of your needs. three if/else or one line using `ternary` doesn't make sense of readability at all. Personally I have bunch lines of comment but keep using one-line commands. – Tuyen Pham Nov 09 '18 at 16:40
  • @JeffSchaller In my personal opinion, one liners are good. They make the scripts readable, are most of the times elegant, and easy to share over chat or quick voice calls. Also, they are more maintainable/manageable in large scripts; unless of course they are overly complicated bash porn (e.g: https://askubuntu.com/a/113228 ) like this. This is only my opinion. – BhaveshDiwan Sep 30 '22 at 14:40

2 Answers2

4
mkdir -p ~/tmp/a/b/c/{d,e}
path+=(~/tmp/a ~/tmp/a/**/*(N/))
print -l $path

Which should add both ~/tmp/a to the PATH variable as well as any directories *(/) recursively **. Unlike the linked question this avoids a slow fork out to find(1).

The N qualifier is so as not to consider it an error if there's no (non-hidden) directory in there.

Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501
thrig
  • 34,333
  • 3
  • 63
  • 84
  • Very nice one, I also think use `find` or depends on other utils is `overkill` for this task, luckily. – Tuyen Pham Nov 09 '18 at 16:54
  • 3
    Or combined into `path+=(~/tmp/a{,/**/*(N/)})` – Stéphane Chazelas Nov 09 '18 at 16:57
  • @StéphaneChazelas: How to exclude folder e.g: `.bak` from adding to path? – Tuyen Pham Jan 26 '19 at 05:44
  • 1
    @TuyenPham, you can change `**/*` to `**/^*.bak` (with `extendedglob`) or to also exclude `foo.bak/bar`, still with `extendedglob`: `(^*.bak/)#^*.bak`. (`**/*` is actually short for `(*/)#*` where `#` is a 0-or-more operator like regex `*`) – Stéphane Chazelas Jan 26 '19 at 09:28
  • I wanted to only include one level of directories within `~/tmp/bin` and not end up having `lib` or any other sub-directories in my path. Following worked for me `path+=("${MYTMP}"/bin{,/*(N/)})` – BhaveshDiwan Sep 30 '22 at 14:33
2

Consider also stow.

stow is a tool that allows you to create a set of packages in sub-directories: It helps keep things separate, while keeping them together. It does this by create links to them in a root directory (e.g. ~/bin), and helping you to manage these links when files are added and removed.

It is often used for /usr/local it will link to the various files in various sub-directories (etc, bin, lib …). This way there is no need to update $PATH.

So if you have

  • package1
    • bin
      • bin1
      • bin2
  • package2
    • bin
      • bin3
      • bin4

then you will end up with

  • bin1 -> package1/bin/bin1
  • bin2 -> package1/bin/bin2
  • bin3 -> package2/bin/bin3
  • bin4 -> package2/bin/bin4
  • package1
    • bin
      • bin1
      • bin2
  • package2
    • bin
      • bin3
      • bin4
ctrl-alt-delor
  • 27,473
  • 9
  • 58
  • 102