una scripts script programas pasar parametros operaciones manejo for eliminar ejemplos caracteres cadenas cadena aritmeticas bash scripting tilde tilde-expansion

programas - scripts bash ejemplos



Cómo expandir manualmente una variable especial(por ejemplo: ~ tilde) en bash (13)

Tengo una variable en mi script bash cuyo valor es algo como esto:

~/a/b/c

Tenga en cuenta que es tilde no expandida. Cuando hago ls -lt en esta variable (llámala $ VAR), no obtengo tal directorio. Quiero dejar que bash interprete / expanda esta variable sin ejecutarla. En otras palabras, quiero que bash ejecute eval pero no ejecute el comando evaluado. ¿Es esto posible en bash?

¿Cómo logré pasar esto a mi script sin expansión? Pasé la discusión rodeándola con comillas dobles.

Prueba este comando para ver lo que quiero decir:

ls -lt "~"

Esta es exactamente la situación en la que estoy. Quiero que la tilde se expanda. En otras palabras, ¿con qué debería reemplazar la magia para que estos dos comandos sean idénticos?

ls -lt ~/abc/def/ghi

y

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

Tenga en cuenta que ~ / abc / def / ghi puede existir o no.


Aquí está la función POSIX equivalente a la answer Bash de Håkon Hægland

expand_tilde() { tilde_less="${1#/~/}" [ "$1" != "$tilde_less" ] && tilde_less="$HOME/$tilde_less" printf ''%s'' "$tilde_less" }

2017-12-10 editar: agrega ''%s'' por @CharlesDuffy en los comentarios.


Aquí está mi solución:

#!/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"


Creo que esto es lo que estás buscando

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.$$ }

Ejemplo de uso:

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


Expandir (sin juego de palabras) en las respuestas de birryree y halloleo: El enfoque general es usar eval , pero viene con algunas advertencias importantes, a saber, espacios y redirección de salida ( > ) en la variable. Lo siguiente parece funcionar para mí:

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

Pruébalo con cada uno de los siguientes argumentos:

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

Explicación

  • Los ${mypath//>} eliminan los caracteres que podrían dañar un archivo durante la eval .
  • El eval echo ... es lo que hace la expansión real de tilde
  • Las comillas dobles alrededor del argumento -e son para apoyar nombres de archivos con espacios.

Tal vez hay una solución más elegante, pero esto es lo que pude encontrar.


Placerizarme a mí mismo de una respuesta anterior , para hacer esto de forma robusta sin los riesgos de seguridad asociados con 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%:}" }

...Usado como...

path=$(expandPath ''~/hello'')

Alternativamente, un enfoque más simple que usa eval cuidado:

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 }


Puede encontrar esto más fácil de hacer en Python.

(1) Desde la línea de comando de Unix:

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

Resultados en:

/Users/someone/fred

(2) Dentro de un script bash como único: guarde esto como test.sh :

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

Ejecutar bash ./test.sh resultados en:

/Users/someone/fred

(3) Como utilidad: guárdelo como expanduser algún lugar de su ruta, con permisos de ejecución:

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

Esto podría ser utilizado en la línea de comando:

expanduser ~/fred

O en una secuencia de comandos:

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


Qué tal esto:

path=`realpath "$1"`

O:

path=`readlink -f "$1"`


Si la variable var es ingresada por el usuario, eval no debe usarse para expandir la tilde usando

eval var=$var # Do not use this!

La razón es: el usuario podría por accidente (o por propósito) escribir por ejemplo var="$(rm -rf $HOME/)" con posibles consecuencias desastrosas.

Una forma mejor (y más segura) es usar la expansión del parámetro Bash:

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


Solo para extender la respuesta de birryree para rutas con espacios: No puede usar el comando eval como está porque separa la evaluación por espacios. Una solución es reemplazar espacios temporalmente para el comando eval:

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

Este ejemplo se basa, por supuesto, en la suposición de que mypath nunca contiene la secuencia char "_spc_" .


Solo use eval correctamente: con validación.

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


Una forma segura de usar eval es "$(printf "~/%q" "$dangerous_path")" . Tenga en cuenta que es específico de bash.

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

Ver esta pregunta para más detalles

Además, tenga en cuenta que bajo zsh esto sería tan simple como echo ${~dangerous_path}


Debido a la naturaleza de , no puedo simplemente dejar esta respuesta inaceptable, pero en los 5 años transcurridos desde que publiqué esto, ha habido respuestas mucho mejores que mi respuesta ciertamente rudimentaria y bastante mala (yo era joven, no mate yo).

Las otras soluciones en este hilo son soluciones más seguras y mejores. Preferiblemente, iría con cualquiera de estos dos:

  • La solución de Duffy de Charle
  • La solución de Håkon Hægland

Respuesta original para fines históricos (pero no la use)

Si no me equivoco, "~" no será expandido por un script bash de esa manera porque se trata como una cadena literal "~" . Puede forzar la expansión a través de eval como este.

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

Alternativamente, simplemente use ${HOME} si quiere el directorio de inicio del usuario.


Lo más simple : reemplace ''magia'' con ''eval echo''.

$ eval echo "~" /whatever/the/f/the/home/directory/is

Problema: Vas a encontrar problemas con otras variables porque eval es malo. Por ejemplo:

$ # home is /Users/Hacker$(s) $ s="echo SCARY COMMAND" $ eval echo $(eval echo "~") /Users/HackerSCARY COMMAND

Tenga en cuenta que el problema de la inyección no ocurre en la primera expansión. Entonces, si reemplazases simplemente magic con eval echo , deberías estar bien. Pero si haces echo $(eval echo ~) , eso sería susceptible de inyección.

De forma similar, si realiza el eval echo ~ lugar del eval echo "~" de eval echo "~" , eso contaría como dos veces expandido y, por lo tanto, la inyección sería posible de inmediato.