Tengo una variable en mi script bash cuyo valor es algo como esto:
~/a/b/c
Tenga en cuenta que es tilde sin expandir. Cuando hago ls -lt en esta variable (lo llamo $ 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é el argumento rodeándolo con comillas dobles.
Prueba este comando para ver a qué me refiero:
ls -lt "~"
Esta es exactamente la situación en la que estoy. Quiero que se expanda la tilde. En otras palabras, ¿con qué debería reemplazar la magia para hacer 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 o no existir.
fuente

eval.foo=~/"$filepath"ofoo="$HOME/$filepath"dir="$(readlink -f "$dir")"Respuestas:
Debido a la naturaleza de StackOverflow, no puedo simplemente hacer que esta respuesta sea 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 (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:
Respuesta original para fines históricos (pero no use esto)
Si no me equivoco,
"~"un script bash no lo expandirá de esa manera porque se trata como una cadena literal"~". Puede forzar la expansión deevalesta manera.Alternativamente, solo use
${HOME}si desea el directorio de inicio del usuario.fuente
${HOME}más atractivo. ¿Hay alguna razón para no hacer de esta su recomendación principal? En cualquier caso, gracias!evales una sugerencia horrible, es realmente malo que reciba tantos votos positivos. Te encontrarás con todo tipo de problemas cuando el valor de la variable contenga meta caracteres de shell.Si la variable
vares de entrada por el usuario,evaldebe no ser utilizado para expandir el tilde usandoLa razón es: el usuario podría escribir por accidente (o por propósito), por ejemplo,
var="$(rm -rf $HOME/)"con posibles consecuencias desastrosas.Una forma mejor (y más segura) es usar la expansión de parámetros Bash:
fuente
#en"${var/#\~/$HOME}"?$var.\~es decir, escapar~? (2) Su respuesta asume que ese~es el primer personaje en$var. ¿Cómo podemos ignorar los espacios en blanco principales$var?:cadena sin comillas. Más información en los documentos . Para eliminar el espacio en blanco inicial, consulte ¿Cómo recortar espacios en blanco de una variable Bash?Plagarme de una respuesta anterior , para hacer esto de manera robusta sin los riesgos de seguridad asociados con
eval:...Usado como...
Alternativamente, un enfoque más simple que utiliza con
evalcuidado:fuente
printf %qpara escapar de todo, pero la tilde, y luego usarevalsin riesgo.Una forma segura de usar eval es
"$(printf "~/%q" "$dangerous_path")". Tenga en cuenta que es bash específico.Ver esta pregunta para más detalles
Además, tenga en cuenta que bajo zsh esto sería tan simple como
echo ${~dangerous_path}fuente
echo ${~root}no me dé salida en zsh (mac os x)export test="~root/a b"; echo ${~test}Qué tal esto:
O:
fuente
realpathcomando de ejemplo C. Para, puede generar un archivo ejecutablerealpath.exeutilizando fiesta y gcc de esta línea de comandos:gcc -o realpath.exe -x c - <<< $'#include <stdlib.h> \n int main(int c,char**v){char p[9999]; realpath(v[1],p); puts(p);}'. Saludosrealpath ~->/home/myhome<workingdir>/~.Ampliación (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í:Pruébelo con cada uno de los siguientes argumentos:
Explicación
${mypath//>}excluye los>caracteres que podrían Clobber un archivo durante eleval.eval echo ...es lo que hace la expansión tilde real-eargumento son para soportar nombres de archivos con espacios.Quizás haya una solución más elegante, pero esto es lo que pude encontrar.
fuente
$(rm -rf .).>embargo, ¿no se rompe esto en los caminos que realmente contienen caracteres?Creo que esto es lo que estás buscando.
Ejemplo de uso:
fuente
printf %qno escape a tildes principales: es casi tentador presentar esto como un error, ya que es una situación en la que falla en su propósito declarado. Sin embargo, mientras tanto, ¡una buena decisión!Aquí está mi solución:
fuente
echoeso significa queexpandTilde -nno se comportará como se esperaba, y POSIX no define el comportamiento con nombres de archivo que contienen barras invertidas. Ver pubs.opengroup.org/onlinepubs/009604599/utilities/echo.htmlSolo use
evalcorrectamente: con validación.fuente
printf %qescapará de las cosas de manera más segura de lo que confío en que el código de validación escrito a mano no tenga errores .printfes un$PATHcomando 'd.bash? Si es así,printfestá integrado y%qse garantiza que estará presente.bashsuficiente antes para saber que no confías en él. probar:x=$(printf \\1); [ -n "$x" ] || echo but its not null!Aquí está la función POSIX equivalente a la respuesta Bash de Håkon Hægland
2017-12-10 edit: agregar
'%s'por @CharlesDuffy en los comentarios.fuente
printf '%s\n' "$tilde_less", ¿quizás? De lo contrario, se comportará mal si el nombre de archivo que se expande contiene barras invertidas%su otra sintaxis significativa paraprintf. Sin embargo, aparte de eso, esta es una gran respuesta: correcta (cuando las extensiones bash / ksh no necesitan ser cubiertas), obviamente segura (sin muckeval) y conciso.¿por qué no profundizar directamente en obtener el directorio de inicio del usuario con getent?
fuente
Solo para extender la respuesta de birryree para rutas con espacios: No puede usar el
evalcomando tal como está porque separa la evaluación por espacios. Una solución es reemplazar espacios temporalmente para el comando eval:Este ejemplo se basa, por supuesto, en el supuesto de que
mypathnunca contiene la secuencia de caracteres"_spc_".fuente
$(rm -rf .)Puede encontrar esto más fácil de hacer en Python.
(1) Desde la línea de comando de Unix:
Resultados en:
(2) Dentro de un script bash como único: guarde esto como
test.sh:bash ./test.shResultados en ejecución en:(3) Como una utilidad: guarde esto como en
expanduseralgún lugar de su ruta, con permisos de ejecución:Esto podría usarse en la línea de comando:
O en un guión:
fuente
echo $thepathtiene errores debe serecho "$thepath"para arreglar los casos menos comunes (nombres con tabulaciones o series de espacios que se convierten en espacios individuales; nombres con globos que los tienen expandidos), o tambiénprintf '%s\n' "$thepath"para corregir los casos poco comunes (es decir, un archivo llamado-no un archivo con literales de barra invertida en un sistema compatible con XSI). Del mismo modo,thepath=$(expanduser "$1")echocomportarse de una manera completamente definida por la implementación si algún argumento contiene barras invertidas; Las extensiones XSI opcionales a POSIX exigen comportamientos de expansión predeterminados (no necesarios-eo-Enecesarios) para dichos nombres.Más simple : reemplace 'magia' con 'eval echo'.
Problema: Te encontrarás con problemas con otras variables porque eval es malo. Por ejemplo:
Tenga en cuenta que el problema de la inyección no ocurre en la primera expansión. Entonces, si simplemente reemplazaras
magicconeval echo, deberías estar bien. Pero si lo haceecho $(eval echo ~), eso sería susceptible a la inyección.Del mismo modo, si lo hace en
eval echo ~lugar deeval echo "~", eso contaría como dos veces expandido y, por lo tanto, la inyección sería posible de inmediato.fuente
s='echo; EVIL_COMMAND'. (Se fallará porqueEVIL_COMMANDno existe en su computadora, pero si ese comando había sido.rm -r ~Por ejemplo, se habría eliminado el directorio de inicio.)He hecho esto con la sustitución de parámetros variables después de leer en la ruta usando read -e (entre otros). Por lo tanto, el usuario puede completar la ruta con pestañas, y si el usuario ingresa una ruta ~ se ordena.
El beneficio adicional es que si no hay tilde no pasa nada a la variable, y si hay una tilde pero no en la primera posición, también se ignora.
(Incluyo el -i para leer, ya que lo uso en un bucle para que el usuario pueda corregir la ruta si hay un problema).
fuente