Blog coding and discussion of coding about JavaScript, PHP, CGI, general web building etc.

Saturday, December 12, 2015

How to manually expand a special variable (ex: ~ tilde) in bash

How to manually expand a special variable (ex: ~ tilde) in bash


I have a variable in my bash script whose value is something like this:

~/a/b/c  

Note that it is unexpanded tilde. When I do ls -lt on this variable (call it $VAR), I get no such directory. I want to let bash interpret/expand this variable without executing it. In other words, I want bash to run eval but not run the evaluated command. Is this possible in bash?

How did I manage to pass this into my script without expansion? I passed the argument in surrounding it with double quotes.

Try this command to see what I mean:

ls -lt "~"  

This is exactly the situation I am in. I want the tilde to be expanded. In other words, what should I replace magic with to make these two commands identical:

ls -lt ~/abc/def/ghi  

and

ls -lt $(magic "~/abc/def/ghi")  

Note that ~/abc/def/ghi may or may not exist.

Answer by birryree for How to manually expand a special variable (ex: ~ tilde) in bash


Due to the nature of StackOverflow, I can't just make this answer unaccepted, but in the intervening 5 years since I posted this there have been far better answers than my admittedly rudimentary and pretty bad answer (I was young, don't kill me).

The other solutions in this thread are safer and better solutions. Preferably, I'd go with either of these two:


Original answer for historic purposes (but please don't use this)

If I'm not mistaken, "~" will not be expanded by a bash script in that manner because it is treated as a literal string "~". You can force expansion via eval like this.

#!/bin/bash    homedir=~  eval homedir=$homedir  echo $homedir # prints home path  

Alternatively, just use ${HOME} if you want the user's home directory.

Answer by Jay for How to manually expand a special variable (ex: ~ tilde) in bash


How about this:

path=`realpath "$1"`  

Or:

path=`readlink -f "$1"`  

Answer by halloleo for How to manually expand a special variable (ex: ~ tilde) in bash


Just to extend birryree's answer for paths with spaces: You cannot use the eval command as is because it seperates evaluation by spaces. One solution is to replace spaces temporarily for the eval command:

mypath="~/a/b/c/Something With Spaces"  expandedpath=${mypath// /_spc_}    # replace spaces   eval expandedpath=${expandedpath}  # put spaces back  expandedpath=${expandedpath//_spc_/ }  echo "$expandedpath"    # prints e.g. /Users/fred/a/b/c/Something With Spaces"  ls -lt "$expandedpath"  # outputs dir content  

This example relies of course on the assumption that mypath never contains the char sequence "_spc_".

Answer by Noach Magedman for How to manually expand a special variable (ex: ~ tilde) in bash


Expanding (no pun intended) on birryree's and halloleo's answers: The general approach is to use eval, but it comes with some important caveats, namely spaces and output redirection (>) in the variable. The following seems to work for me:

mypath="$1"    if [ -e "`eval echo ${mypath//>}`" ]; then      echo "FOUND $mypath"  else      echo "$mypath NOT FOUND"  fi  

Try it with each of the following arguments:

'~'  '~/existing_file'  '~/existing file with spaces'  '~/nonexistant_file'  '~/nonexistant file with spaces'  '~/string containing > redirection'  '~/string containing > redirection > again and >> again'  

Explanation

  • The ${mypath//>} strips out > characters which could clobber a file during the eval.
  • The eval echo ... is what does the actual tilde expansion
  • The double-quotes around the -e argument are for support of filenames with spaces.

Perhaps there's a more elegant solution, but this is what I was able to come up with.

Answer by eddygeek for How to manually expand a special variable (ex: ~ tilde) in bash


A safe way to use eval is "$(printf "~/%q" "$dangerous_path")". Note that is bash specific.

#!/bin/bash    relativepath=a/b/c  eval homedir="$(printf "~/%q" "$relativepath")"  echo $homedir # prints home path  

See this question for details

Also, note that under zsh this would be as as simple as echo ${~dangerous_path}

Answer by H?kon H?gland for How to manually expand a special variable (ex: ~ tilde) in bash


If the variable var is input by the user, eval should not be used to expand the tilde using

eval var=$var  # Do not use this!  

The reason is: the user could by accident (or by purpose) type for example var="$(rm -rf $HOME/)" with possible disastrous consequences.

A better (and safer) way is to use Bash parameter expansion:

var="${var/#\~/$HOME}"  

Answer by Charles Duffy for How to manually expand a special variable (ex: ~ tilde) in bash


Plagarizing myself from a prior answer, to do this robustly without the security risks associated with eval:

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

...used as...

path=$(expandPath '~/hello')  

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  }  

Answer by Orwellophile for How to manually expand a special variable (ex: ~ tilde) in bash


I believe this is what you're looking for

magic() { # returns unexpanded tilde express on invalid user      local _safe_path; printf -v _safe_path "%q" "$1"      eval "ln -sf ${_safe_path#\\} /tmp/realpath.$$"      readlink /tmp/realpath.$$      rm -f /tmp/realpath.$$  }  

Example usage:

$ magic ~nobody/would/look/here  /var/empty/would/look/here    $ magic ~invalid/this/will/not/expand  ~invalid/this/will/not/expand  

Answer by Gino for How to manually expand a special variable (ex: ~ tilde) in bash


Here's my solution:

#!/bin/bash      expandTilde()  {      local tilde_re='^(~[A-Za-z0-9_.-]*)(.*)'      local path="$*"      local pathSuffix=        if [[ $path =~ $tilde_re ]]      then          # only use eval on the ~username portion !          path=$(eval echo ${BASH_REMATCH[1]})          pathSuffix=${BASH_REMATCH[2]}      fi        echo "${path}${pathSuffix}"  }        result=$(expandTilde "$1")    echo "Result = $result"  

Answer by Chris Johnson for How to manually expand a special variable (ex: ~ tilde) in bash


You might find this easier to do in python.

(1) From the unix command line:

python -c 'import os; import sys; print os.path.expanduser(sys.argv[1])' ~/fred  

Results in:

/Users/someone/fred  

(2) Within a bash script as a one-off - save this as test.sh:

#!/usr/bin/env bash    thepath=$(python -c 'import os; import sys; print os.path.expanduser(sys.argv[1])' $1)    echo $thepath  

Running bash ./test.sh results in:

/Users/someone/fred  

(3) As a utility - save this as expanduser somewhere on your path, with execute permissions:

#!/usr/bin/env python    import sys  import os    print os.path.expanduser(sys.argv[1])  

This could then be used on the command line:

expanduser ~/fred  

Or in a script:

#!/usr/bin/env bash    thepath=$(expanduser $1)    echo $thepath  

Answer by mikeserv for How to manually expand a special variable (ex: ~ tilde) in bash


Just use eval correctly: with validation.

case $1${1%%/*} in  ([!~]*|"$1"?*[!-+_.[:alnum:]]*|"") ! :;;  (*/*)  set "${1%%/*}" "${1#*/}"       ;;  (*)    set "$1"   esac&& eval "printf '%s\n' $1${2+/\"\$2\"}"  


Fatal error: Call to a member function getElementsByTagName() on a non-object in D:\XAMPP INSTALLASTION\xampp\htdocs\endunpratama9i\www-stackoverflow-info-proses.php on line 71

0 comments:

Post a Comment

Popular Posts

Powered by Blogger.