Change directory to a path specified in a file with tilde

走远了吗. 提交于 2019-12-03 18:12:15

问题


I have a file, say: ~/cwd. The content of this file is a single line:

~/tmp

I want fo cd to this (~/tmp) dir. I'm trying:

> cd `cat ~/cwd`

And got:

-bash: cd: ~/tmp: No such file or directory

Why the RELATIVE paths failed? When the content of the ~/cwd is absolute path - it works.


回答1:


Try this:

eval cd `cat ~/cwd`

The '~' needs to be expanded by the shell. The eval causes the command to be run through the shell's command processing, which includes '~' expansion.




回答2:


It's not a problem with relative paths -- this happens because the shell evaluation model does tilde expansion BEFORE parameter expansion. Skipping back up to the very beginning of the evaluation process, with eval, introduces security bugs -- so if one REALLY needs to support this (and I argue, strongly, that it's a bad idea), a safe implementation (targeting platforms with the getent command available) would look like the following:

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

...to use this for a path read from a file safely:

printf '%s\n' "$(expandPath "$(<file)")"

Alternately, a simpler approach that uses eval carefully:

expandPath() {
  case $1 in
    ~[+-]*)
      local content content_q
      printf -v content_q '%q' "${1:2}"
      eval "content=${1:0:2}${content_q}"
      printf '%s\n' "$content"
      ;;
    ~*)
      local content content_q
      printf -v content_q '%q' "${1:1}"
      eval "content=~${content_q}"
      printf '%s\n' "$content"
      ;;
    *)
      printf '%s\n' "$1"
      ;;
  esac
}



回答3:


Use eval:

eval cd $(cat file)

Otherwise the shell will not be able to interpret the meaning of ~.




回答4:


Without the need of cat:

eval cd "$(<~/cwd)"


来源:https://stackoverflow.com/questions/18740167/change-directory-to-a-path-specified-in-a-file-with-tilde

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!