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 theeval
. - 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