5

Context

  • linux bash
  • pushd/popd/dirs

Problem

The problem scenario is very similar to the one stated in this question: removing or clearing stack of popd/pushd paths ... however the goal is not to clear the stack, but rather to prune it. Specifically, the pruning operation is to remove duplicates.

Question

Is there a straightforward way to prune the output of dirs -v -p such that there are no duplicates in the stack?

3
  • 3
    In zsh, setopt pushd_ignore_dups makes this systematic. Commented Jun 8, 2016 at 22:34
  • 1
    @Gilles: yeah, all the cool kids keep telling me to use zsh ...
    – dreftymac
    Commented Jun 8, 2016 at 22:41
  • I'm a zsh user who thinks bash should be good enough but when something like this comes up, I keep realizing reality is slightly different. But unlike fish shell, you really don't lose anything by migrating from bash to zsh...I THINK. Commented May 20 at 23:19

1 Answer 1

3

This function should remove dups.

dedup(){
    declare -a new=() copy=("${DIRSTACK[@]:1}")
    declare -A seen
    local v i
    seen[$PWD]=1
    for v in "${copy[@]}"
    do if [ -z "${seen[$v]}" ]
       then new+=("$v")
            seen[$v]=1
       fi
    done
    dirs -c
    for ((i=${#new[@]}-1; i>=0; i--))
    do      builtin pushd -n "${new[i]}" >/dev/null
    done
}

It copies the list of dirs, except the first which is bogus, into an array copy, and for each dir adds it to a new array if we have not already seen it (an associative array). This ensures older dup entries, which are later in the array, are not copied. The dir list is cleared, and the array is then pushd in reverse order.

The first bogus element of the dirs list is the current directory, which is unchanged. It is set in the seen array at the start to also get it removed if earlier in the dir list.

If you want to do this automatically, you can override pushd eg:

pushd(){
    builtin pushd "$@"
    dedup
}
3
  • I suggest adding double quotes around $PWD and $v, in case you have directory names with spaces in them (lamentably common on some systems). Commented Dec 6, 2019 at 1:24
  • It doesn't seem to be necessary with bash in the particular case of an index in array[index]=..., but you are right that in general you should double-quote variables, and there is no harm in doing so in this case.
    – meuh
    Commented Dec 6, 2019 at 15:32
  • Also, in your pushd() function, the builtin pushd command prints the directory stack. In this case, it will print the stack before it's de-duplicated. Suggested change: pushd() { builtin pushd "$@" >/dev/null ; dedup ; dirs ; } (not tested). Commented Dec 6, 2019 at 18:32

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .