1

I tend to visit the same directories during the course of a workday. Using the dirs -v command I can keep a list in a file

dirs -v > last-lines.txt

I would like to be able to re-read this file in a new terminal and pushd to each directory on the line. What I have is

cat ~/last-list.txt | while read line; do pushd $line; done

the issue I am having is that the '~' is not expanded and as a result the pushd fails with

-bash: pushd: ~/director-name: No such file or directory

Is there anyway to force '~' to be expanded to the full path, or a smarter way to accomplish the above?

Thanks

Jahid
  • 21,542
  • 10
  • 90
  • 108
  • 1
    note you can say `while read -r line; do pushd ...; done < ~/last-list.txt` instead of `cat | while ...`. – fedorqui Jun 02 '15 at 15:27
  • 1
    My current attempt at a maximally complete answer is http://stackoverflow.com/a/18742860/14122. That said, arguably the easier answer is not to support tilde expansion in your data files -- it's not a common feature in noninteractive use. – Charles Duffy Jun 02 '15 at 15:32
  • 1
    BTW -- directory names can have literal newlines in them. Reading them from a newline-delimited file, then, isn't exactly a great practice. (Also, they can end in whitespace, so you'd need to clear `IFS` during the read, and they can contain literal backslashes, so you'd need to pass `-r` to the read command as well, if you want to cover all the corner cases). – Charles Duffy Jun 02 '15 at 15:34

1 Answers1

1

Change pushd $line; to:

pushd "${line/#\~/$HOME}";

~ will be expanded to $HOME

Note: Use double quotation to handle white spaces in path

You are making useless use of cat. It's not needed here at all.

To read line from file:

while IFS= read -r line;do
#do something
done < filepath

A complete but more complex solution from Charles Duffys' answer to this question

expandPath() {
  local path
  local -a pathElements resultPathElements
  IFS=':' read -r -a pathElements <<<"$1"
  : "${pathElements[@]}"
  for path in "${pathElements[@]}"; do
    : "$path"
    case $path in
      "~+"/*)
        path=$PWD/${path#"~+/"}
        ;;
      "~-"/*)
        path=$OLDPWD/${path#"~-/"}
        ;;
      "~"/*)
        path=$HOME/${path#"~/"}
        ;;
      "~"*)
        username=${path%%/*}
        username=${username#"~"}
        IFS=: read _ _ _ _ _ homedir _ < <(getent passwd "$username")
        if [[ $path = */* ]]; then
          path=${homedir}/${path#*/}
        else
          path=$homedir
        fi
        ;;
    esac
    resultPathElements+=( "$path" )
  done
  local result
  printf -v result '%s:' "${resultPathElements[@]}"
  printf '%s\n' "${result%:}"
}

Usage:

pushd "$(expandPath "$line")"

"$(expandPath "$line")" is the expanded path

Community
  • 1
  • 1
Jahid
  • 21,542
  • 10
  • 90
  • 108