Tengo una función bash para establecer $PATH
así:
assign-path()
{
str=$1
# if the $PATH is empty, assign it directly.
if [ -z $PATH ]; then
PATH=$str;
# if the $PATH does not contain the substring, append it with ':'.
elif [[ $PATH != *$str* ]]; then
PATH=$PATH:$str;
fi
}
Pero el problema es que tengo que escribir diferentes funciones para diferentes variables (por ejemplo, otra función para me $CLASSPATH
gusta, assign-classpath()
etc.). No pude encontrar una manera de pasar argumentos a la función bash para poder acceder a ella por referencia.
Sería mejor si tuviera algo como ...
assign( bigstr, substr )
{
if [ -z bigstr ]; then
bigstr=substr;
elif [[ bigstr != *str* ]]; then
bigstr=bigstr:substr;
fi
}
Alguna idea, ¿cómo lograr algo como lo anterior en bash?
bash
bash-script
ramgorur
fuente
fuente
assign-path /abc
No anexará/abc
al PATH $ PATH si ya contiene/abc/def
,/abcd
,/def/abc
etc. Sobre todo no se puede agregar/bin
si la ruta ya contiene/usr/bin
.$PATH
y prueba negate contra sus argumentos como:add=/bin dir=/usr/bin ; [ -z "${dir%"$add"}" ] || dir="${dir}:${add}"
. En mi respuesta, lo hago de esta manera con tantos argumentos como quieras solo usandoIFS=:
.$PATH
? y Agregar directorio a$PATH
si aún no está allí (en Super Usuario ).Respuestas:
En
bash
puede utilizar${!varname}
para expandir la variable referenciada por el contenido de otra. P.ej:Desde la página del manual:
Además, para establecer una variable referenciada por los contenidos (sin los peligros de
eval
), puede usardeclare
. P.ej:Por lo tanto, podría escribir su función de esta manera (tenga cuidado porque si usa
declare
una función, debe dar-g
o la variable será local):Y úsalo como:
Tenga en cuenta que también he corregido un error en el que si
substr
ya es una subcadena de uno de los miembros separados por dos puntosbigstr
, pero no su propio miembro, entonces no se agregaría. Por ejemplo, esto permitiría agregar/bin
a unaPATH
variable que ya contiene/usr/bin
. Utiliza losextglob
conjuntos para hacer coincidir el principio / final de la cadena o dos puntos y luego cualquier otra cosa. Sinextglob
, la alternativa sería:fuente
-g
indeclare
no está disponible en la versión anterior de bash, ¿hay alguna manera de que pueda hacer que esto sea compatible con versiones anteriores?export
para ponerlo en su entorno (a riesgo de sobrescribir algo importante) oeval
(varios problemas, incluida la seguridad, si no tiene cuidado). Si lo usaeval
, debería estar bien si lo hace asíeval "$target=\$substr"
. Sin\
embargo, si olvida esto, potencialmente ejecutará un comando si hay un espacio en el contenido desubstr
.Nuevo en bash 4.3, es la
-n
opción dedeclare
&local
:Eso se imprime
hello, world
.fuente
Puede usar
eval
para establecer un parámetro. Una descripción de este comando se puede encontrar aquí . El siguiente uso deeval
es incorrecto:Con respecto a la evaluación adicional
eval
, debe usarVerifique los resultados del uso de estas funciones:
Pero puede lograr su objetivo sin el uso de
eval
. Prefiero esta manera que es más simple.La siguiente función hace la sustitución de la manera correcta (espero)
Comprueba la siguiente salida
Ahora puede usar la
augment
función de la siguiente manera para establecer una variable:fuente
v='echo "OHNO!" ; var' ; l=val ; eval $v='$l'
- haría eco de "OHNO! Antes de asignar var. Puede" $ {v ## * [; "$ IFS"]} = '$ l' "para asegurarse de que la cadena no se puede expandir a nada que no será evaluado con el =.=
declaración de asignación. Puede argumentar que mi script no verifica su argumento. Eso es verdad. Ni siquiera verifico si hay algún argumento o si el número de argumentos es válido. Pero esto fue por intención. El OP puede agregar tales controles si lo desea.v
(mejor su valor) como segundo argumento de la función de asignación. Por lo tanto, su valor debe estar en el lado derecho de una asignación. Es necesario citar el argumento de la funciónassign
. Agregué esta sutileza a mi publicación.Con algunos trucos, puede pasar parámetros con nombre a funciones, junto con arreglos (probados en bash 3 y 4).
El método que desarrollé le permite acceder a los parámetros pasados a una función como esta:
En otras palabras, no solo puede llamar a sus parámetros por sus nombres (lo que compensa un núcleo más legible), sino que también puede pasar matrices (y referencias a variables; ¡esta función solo funciona en bash 4.3)! Además, todas las variables asignadas están en el ámbito local, igual que $ 1 (y otras).
El código que hace que esto funcione es bastante ligero y funciona tanto en bash 3 como en bash 4 (estas son las únicas versiones con las que lo he probado). Si está interesado en más trucos como este que hacen que desarrollar con bash sea mucho más fácil y fácil, puede echar un vistazo a mi Bash Infinity Framework , el código a continuación fue desarrollado para ese propósito.
fuente
¿Esto encaja?
fuente
eval
es susceptible a la ejecución arbitraria de comandos.eval
líneas zhe sean más seguras? Normalmente, cuando creo que necesito evaluar, decido no usar * sh y cambiar a un idioma diferente. Por otro lado, al usar esto en scripts para agregar entradas a algunas variables similares a PATH, se ejecutará con constantes de cadena y no entrada del usuario ...eval
manera segura, pero requiere mucha reflexión. Si solo está tratando de hacer referencia a un parámetro, querría hacer algo como esto: deeval "$1=\"\$2\""
esa manera, en laeval's
primera pasada, solo evalúa $ 1 y en la segunda, tiene valor = "$ 2". Pero debe hacer otra cosa, esto es innecesario aquí."${1##*[;"$IFS"]}=\"\$2\""
, e incluso eso no tiene garantía. Oeval "$(set -- $1 ; shift $(($#-1)) ; echo $1)=\"\$2\""
. No es fácil.Los argumentos con nombre simplemente no son cómo se diseñó la sintaxis de Bash. Bash fue diseñado para ser una mejora iterativa sobre el shell Bourne. Como tal, debe asegurarse de que ciertas cosas funcionen entre los dos depósitos tanto como sea posible. Por lo tanto, no está destinado a ser más fácil de escribir en general, solo está destinado a ser mejor que Bourne al tiempo que garantiza que si lleva un script de un entorno Bourne a
bash
lo más fácil posible. Eso no es trivial ya que muchos proyectiles todavía tratan a Bourne como un estándar de facto. Dado que las personas escriben sus scripts para que sean compatibles con Bourne (para esta portabilidad), la necesidad sigue vigente y es poco probable que cambie.Probablemente sea mejor mirar un script de shell diferente (como
python
o algo) por completo si es factible. Si se encuentra con las limitaciones de un idioma, debe comenzar a usar un nuevo idioma.fuente
bash
la vida esto era cierto. Pero ahora se hacen provisiones específicas. Las variables de referencia completas ahora están disponibles enbash 4.3
- vea la respuesta de derobert .Con la
sh
sintaxis estándar (funcionaría enbash
, y no solo enbash
), podría hacer:Al igual que para las soluciones que usan
bash
'sdeclare
, es seguro siempre que$1
contenga un nombre de variable válido.fuente
EN ARGOS NOMBRADOS:
Esto se hace de manera muy simple y
bash
no se requiere en absoluto: este es el comportamiento básico de asignación especificado por POSIX a través de la expansión de parámetros:Para hacer una demostración de una manera similar a @Graeme, pero de forma portátil:
Y allí solo hago
str=
para asegurarme de que tenga un valor nulo, porque la expansión de parámetros tiene la protección incorporada contra la reasignación del entorno de shell en línea si ya está configurado.SOLUCIÓN:
Para su problema específico, no creo que los argumentos nombrados sean necesarios, aunque ciertamente son posibles. Use en su
$IFS
lugar:Esto es lo que obtengo cuando lo ejecuto:
¿Notó que solo agregó los argumentos que aún no estaban incluidos
$PATH
o que aparecieron antes? ¿O incluso que tomó más de un argumento?$IFS
es útilfuente
assign
aquí. Si tiene preguntas sobre cómo funciona, me complacería responder. Y, por cierto, si realmente quieres argumentos con nombre, quizás quieras ver esta otra respuesta mía en la que muestro cómo declarar una función nombrada para los argumentos de otra función: unix.stackexchange.com/a/120531/52934No puedo encontrar nada como rubí, pitón, etc., pero esto se siente más cerca de mí.
La legibilidad es mejor en mi opinión, 4 líneas son excesivas para declarar los nombres de sus parámetros. También se parece más a los idiomas modernos.
fuente
a=$1 b=$2 ...
funciona igual de bien