Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bash path variable using ~ resulting in 'No such file or directory'

Tags:

bash

If I do this:

ls ~/Dev/Project/Assets/_Core/

I get a super duper directory listing! Yay! But if I do this:

assetsPath=$(head -n 1 .config | perl -ne 'print if s/^assets=(.*)/\1/g')
echo $assetsPath
ls $assetsPath

I get:

~/Dev/Project/Assets/_Core/ # this was the variable value from the echo
ls: ~/Dev/Project/Assets/_Core/: No such file or directory

I even tried using ${assetsPath} but that didn't work either?

like image 288
brandonscript Avatar asked Sep 03 '25 10:09

brandonscript


1 Answers

As a partial solution:

assetsPath=${assetsPath//'~'/$HOME}

What this doesn't address is ~username expansion; if your assetsPath uses this, then you need a bit more logic (which I think I've added in a separate StackOverflow answer; looking for the question).


It also doesn't address ~ in non-leading position, where it shouldn't be expanded. To handle both corner cases, I'm going to self-plagarize a bit:

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%:}"
}

...then:

assetsPath=$(expandPath "$assetsPath")
like image 115
Charles Duffy Avatar answered Sep 04 '25 23:09

Charles Duffy