Skip to main content
added 77 characters in body
Source Link
Kusalananda
  • 355.8k
  • 42
  • 735
  • 1.1k

Using bash:

shopt -s globstar
shopt -s dotglob nullglob

dirs=( ./**/*.txt )          # glob the names
dirs=( "${dirs[@]%/*}" )     # remove the filenames at the end

This gives you an array of directory paths with possible duplicates. To delete the duplicates, use an associative array:

declare -A seen
for dirpath in "${dirs[@]}"; do
    seen["$dirpath"]=''
done

dirs=( "${!seen[@]}" )    # extract the keys from the "seen" hash

Then, to print them,

printf '%s\n' "${dirs[@]}"

In the zsh shell, you would do it similarly, but use a unique array and the shell's fancy globbing qualifiers to strip off the filename at the end of the paths:

typeset -U dirs

dirs=( ./**/*.txt(DN:h) )

The D and the N in the globbing qualifier after the pattern acts as dotglob and nullglob in bash, i.e., they enable matching of hidden names and remove the pattern if there are no matches at all. The final :h gives you the "head" of the generated pathnames, i.e., the directory path without the filename at the end.

The zsh shell does not have to enable the use of ** explicitly, as you have to do in bash with setting the globstar shell option.

Then, to print them,

print -r -C1 -- $dirs

Also related:

Using bash:

shopt -s globstar
shopt -s dotglob nullglob

dirs=( ./**/*.txt )          # glob the names
dirs=( "${dirs[@]%/*}" )     # remove the filenames at the end

This gives you an array of directory paths with possible duplicates. To delete the duplicates, use an associative array:

declare -A seen
for dirpath in "${dirs[@]}"; do
    seen["$dirpath"]=''
done

dirs=( "${!seen[@]}" )    # extract the keys from the "seen" hash

Then, to print them,

printf '%s\n' "${dirs[@]}"

In the zsh shell, you would do it similarly, but use a unique array and the shell's fancy globbing qualifiers to strip off the filename at the end of the paths:

typeset -U dirs

dirs=( ./**/*.txt(DN:h) )

The D and the N in the globbing qualifier after the pattern acts as dotglob and nullglob in bash, i.e., they enable matching of hidden names and remove the pattern if there are no matches at all. The final :h gives you the "head" of the generated pathnames, i.e., the directory path without the filename at the end.

The zsh shell does not have to enable the use of ** explicitly, as you have to do in bash with setting the globstar shell option.

Then, to print them,

print -r -C1 -- $dirs

Using bash:

shopt -s globstar
shopt -s dotglob nullglob

dirs=( ./**/*.txt )          # glob the names
dirs=( "${dirs[@]%/*}" )     # remove the filenames at the end

This gives you an array of directory paths with possible duplicates. To delete the duplicates, use an associative array:

declare -A seen
for dirpath in "${dirs[@]}"; do
    seen["$dirpath"]=''
done

dirs=( "${!seen[@]}" )    # extract the keys from the "seen" hash

Then, to print them,

printf '%s\n' "${dirs[@]}"

In the zsh shell, you would do it similarly, but use a unique array and the shell's fancy globbing qualifiers to strip off the filename at the end of the paths:

typeset -U dirs

dirs=( ./**/*.txt(DN:h) )

The D and the N in the globbing qualifier after the pattern acts as dotglob and nullglob in bash, i.e., they enable matching of hidden names and remove the pattern if there are no matches at all. The final :h gives you the "head" of the generated pathnames, i.e., the directory path without the filename at the end.

The zsh shell does not have to enable the use of ** explicitly, as you have to do in bash with setting the globstar shell option.

Then, to print them,

print -r -C1 -- $dirs

Also related:

added 19 characters in body
Source Link
Kusalananda
  • 355.8k
  • 42
  • 735
  • 1.1k

Using bash:

shopt -s globstar
shopt -s dotglob nullglob

dirs=( ./**/*.txt )          # glob the names
dirs=( "${dirs[@]%/*}" )     # remove the filenames at the end

This gives you an array of directory paths with possible duplicates. To delete the duplicates, use an associative array:

declare -A seen
for dirpath in "${dirs[@]}"; do
    seen["$dirpath"]=''
done

dirs=( "${!seen[@]}" )    # extract the keys from the "seen" hash

Then, to print them,

printf '%s\n' "${dirs[@]}"

In the zsh shell, you would do it similarly, but use a unique array and the shell's fancy globbing qualifiers to strip off the filename at the end of the paths:

typeset -U dirs

dirs=( ./**/*.txt(DN:h) )

The D and the N in the globbing qualifier after the pattern acts as dotglob and nullglob in bash, i.e., they enable matching of hidden names and remove the pattern if there are no matches at all. The final :h gives you the "head" of the generated pathnames, i.e., the directory path without the filename at the end.

The zsh shell does not have to enable the use of ** explicitly, as you have to do in bash with setting the globstar shell option.

Then, to print them,

print -r -C1 -- $dirs

Using bash:

shopt -s globstar
shopt -s dotglob nullglob

dirs=( ./**/*.txt )          # glob the names
dirs=( "${dirs[@]%/*}" )     # remove the filenames at the end

This gives you an array with possible duplicates. To delete the duplicates, use an associative array:

declare -A seen
for dirpath in "${dirs[@]}"; do
    seen["$dirpath"]=''
done

dirs=( "${!seen[@]}" )    # extract the keys from the "seen" hash

Then, to print them,

printf '%s\n' "${dirs[@]}"

In the zsh shell, you would do it similarly, but use a unique array and the shell's fancy globbing qualifiers to strip off the filename at the end of the paths:

typeset -U dirs

dirs=( ./**/*.txt(DN:h) )

The D and the N in the globbing qualifier after the pattern acts as dotglob and nullglob in bash, i.e., they enable matching of hidden names and remove the pattern if there are no matches at all. The final :h gives you the "head" of the generated pathnames, i.e., the directory path without the filename at the end.

The zsh shell does not have to enable the use of ** explicitly, as you have to do in bash with setting the globstar shell option.

Then, to print them,

print -r -C1 -- $dirs

Using bash:

shopt -s globstar
shopt -s dotglob nullglob

dirs=( ./**/*.txt )          # glob the names
dirs=( "${dirs[@]%/*}" )     # remove the filenames at the end

This gives you an array of directory paths with possible duplicates. To delete the duplicates, use an associative array:

declare -A seen
for dirpath in "${dirs[@]}"; do
    seen["$dirpath"]=''
done

dirs=( "${!seen[@]}" )    # extract the keys from the "seen" hash

Then, to print them,

printf '%s\n' "${dirs[@]}"

In the zsh shell, you would do it similarly, but use a unique array and the shell's fancy globbing qualifiers to strip off the filename at the end of the paths:

typeset -U dirs

dirs=( ./**/*.txt(DN:h) )

The D and the N in the globbing qualifier after the pattern acts as dotglob and nullglob in bash, i.e., they enable matching of hidden names and remove the pattern if there are no matches at all. The final :h gives you the "head" of the generated pathnames, i.e., the directory path without the filename at the end.

The zsh shell does not have to enable the use of ** explicitly, as you have to do in bash with setting the globstar shell option.

Then, to print them,

print -r -C1 -- $dirs
added 131 characters in body
Source Link
Kusalananda
  • 355.8k
  • 42
  • 735
  • 1.1k

Using bash:

shopt -s globstar
shopt -s dotglob nullglob

dirs=( ./**/*.txt )          # glob the names
dirs=( "${dirs[@]%/*}" )     # remove the filenames at the end

This gives you an array with possible duplicates. To delete the duplicates, use an associative array:

declare -A seen
for dirpath in "${dirs[@]}"; do
    seen["$dirpath"]=''
done

dirs=( "${!seen[@]}" )    # extract the keys from the "seen" hash

Then, to print them,

printf '%s\n' "${dirs[@]}"

In the zsh shell, you would do it in a similar waysimilarly, but use a unique array and the shellsshell's fancy globbing qualifiers to strip off the filename at the end of the paths:

typeset -U dirs

dirs=( ./**/*.txt(DN:h) )

The D and the N in the globbing qualifier after the pattern acts as dotglob and nullglob in bash, i.e., they enable matching of hidden names and will remove the pattern if there are no matches at all. The final :h gives you the "head" of the generated pathnames, i.e., the directory path without the filename at the end.

The zsh shell does not have to enable the use of ** explicitly, as you have to do in bash with setting the globstar shell option.

Then, to print them,

print -r -C1 -- $dirs

Using bash:

shopt -s globstar
shopt -s dotglob nullglob

dirs=( ./**/*.txt )
dirs=( "${dirs[@]%/*}" )

This gives you an array with possible duplicates. To delete the duplicates, use an associative array:

declare -A seen
for dirpath in "${dirs[@]}"; do
    seen["$dirpath"]=''
done

dirs=( "${!seen[@]}" )

Then, to print them,

printf '%s\n' "${dirs[@]}"

In the zsh shell, you would do it in a similar way, but use a unique array and the shells fancy globbing qualifiers to strip off the filename at the end of the paths:

typeset -U dirs

dirs=( ./**/*.txt(DN:h) )

The D and the N in the globbing qualifier after the pattern acts as dotglob and nullglob in bash, i.e. they enable matching of hidden names and will remove the pattern if there are no matches at all. The final :h gives you the "head" of the generated pathnames, i.e. the directory path without the filename at the end.

Then, to print them,

print -r -C1 -- $dirs

Using bash:

shopt -s globstar
shopt -s dotglob nullglob

dirs=( ./**/*.txt )          # glob the names
dirs=( "${dirs[@]%/*}" )     # remove the filenames at the end

This gives you an array with possible duplicates. To delete the duplicates, use an associative array:

declare -A seen
for dirpath in "${dirs[@]}"; do
    seen["$dirpath"]=''
done

dirs=( "${!seen[@]}" )    # extract the keys from the "seen" hash

Then, to print them,

printf '%s\n' "${dirs[@]}"

In the zsh shell, you would do it similarly, but use a unique array and the shell's fancy globbing qualifiers to strip off the filename at the end of the paths:

typeset -U dirs

dirs=( ./**/*.txt(DN:h) )

The D and the N in the globbing qualifier after the pattern acts as dotglob and nullglob in bash, i.e., they enable matching of hidden names and remove the pattern if there are no matches at all. The final :h gives you the "head" of the generated pathnames, i.e., the directory path without the filename at the end.

The zsh shell does not have to enable the use of ** explicitly, as you have to do in bash with setting the globstar shell option.

Then, to print them,

print -r -C1 -- $dirs
Source Link
Kusalananda
  • 355.8k
  • 42
  • 735
  • 1.1k
Loading