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 deeval
esta 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!eval
es 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
var
es de entrada por el usuario,eval
debe 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
eval
cuidado:fuente
printf %q
para escapar de todo, pero la tilde, y luego usareval
sin 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
realpath
comando de ejemplo C. Para, puede generar un archivo ejecutablerealpath.exe
utilizando 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-e
argumento 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 %q
no 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
echo
eso significa queexpandTilde -n
no 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
eval
correctamente: con validación.fuente
printf %q
escapará 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 .printf
es un$PATH
comando 'd.bash
? Si es así,printf
está integrado y%q
se garantiza que estará presente.bash
suficiente 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%s
u 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
eval
comando 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
mypath
nunca 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.sh
Resultados en ejecución en:(3) Como una utilidad: guarde esto como en
expanduser
algú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 $thepath
tiene 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-n
o un archivo con literales de barra invertida en un sistema compatible con XSI). Del mismo modo,thepath=$(expanduser "$1")
echo
comportarse 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-e
o-E
necesarios) 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
magic
coneval 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_COMMAND
no 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