Respuestas:
set
generará las variables, desafortunadamente también generará las funciones definidas.
Afortunadamente, el modo POSIX solo genera las variables:
( set -o posix ; set ) | less
Conectando less
o redireccionando a donde quieras las opciones.
Entonces, para obtener las variables declaradas solo en el script:
( set -o posix ; set ) >/tmp/variables.before
source script
( set -o posix ; set ) >/tmp/variables.after
diff /tmp/variables.before /tmp/variables.after
rm /tmp/variables.before /tmp/variables.after
(O al menos algo basado en eso :-))
VARS="`set -o posix ; set`"; source script; SCRIPT_VARS="`grep -vFe "$VARS" <<<"$(set -o posix ; set)" | grep -v ^VARS=`"; unset VARS;
. Esto también generará las variables en un formato listo para guardar. La lista incluirá las variables que el guión cambiado (que depende de si esto es deseable)
source
, debería poder hacerlo con la salida de declare -p
.
before=$(set -o posix; set); dosomestuff; diff <(echo "$before") <(set -o posix; set)
compgen -v
Enumera todas las variables, incluidas las locales. Lo aprendí de Obtener la lista de variables cuyo nombre coincide con un patrón determinado y lo usé en mi script .
compgen -v
también enumera las variables globales que no se establecieron localmente. No estoy seguro de si se trata de un error de larga data o del comportamiento deseado.
for i in _ {a..z} {A..Z}; do eval "echo \${!$i@}" ; done | xargs printf "%s\n"
Esto debe imprimir todos los nombres de las variables de shell. Puede obtener una lista antes y después de obtener su archivo al igual que con "set" para diferenciar qué variables son nuevas (como se explica en las otras respuestas). Pero tenga en cuenta que dicho filtrado con diff puede filtrar algunas variables que necesita pero que estaban presentes antes de obtener su archivo.
En su caso, si sabe que los nombres de sus variables comienzan con "VARIABLE", entonces puede obtener su script y hacer:
for var in ${!VARIABLE@}; do
printf "%s%q\n" "$var=" "${!var}"
done
ACTUALIZACIÓN: Para una solución BASH pura (no se utilizan comandos externos):
for i in _ {a..z} {A..Z}; do
for var in `eval echo "\\${!$i@}"`; do
echo $var
# you can test if $var matches some criteria and put it in the file or ignore
done
done
eval "printf '%q\n' $(printf ' "${!%s@}"' _ {a..z} {A..Z})"
Según algunas de las respuestas anteriores, esto funcionó para mí:
before=$(set -o posix; set | sort);
archivo fuente :
comm -13 <(printf %s "$before") <(set -o posix; set | sort | uniq)
Si puede posprocesar (como ya se mencionó), puede realizar una set
llamada al principio y al final de su script (cada uno a un archivo diferente) y hacer una diferencia en los dos archivos. Tenga en cuenta que esto todavía contendrá algo de ruido.
También puede hacer esto programáticamente. Para limitar la salida a su alcance actual, tendría que implementar un contenedor para la creación de variables. Por ejemplo
store() {
export ${1}="${*:2}"
[[ ${STORED} =~ "(^| )${1}($| )" ]] || STORED="${STORED} ${1}"
}
store VAR1 abc
store VAR2 bcd
store VAR3 cde
for i in ${STORED}; do
echo "${i}=${!i}"
done
Cuyos rendimientos
VAR1=abc
VAR2=bcd
VAR3=cde
Aquí hay algo similar a la respuesta de @GinkgoFr, pero sin los problemas identificados por @Tino o @DejayClayton, y es más robusto que el set -o posix
bit inteligente de @ DouglasLeeder :
+ function SOLUTION() { (set +o posix; set) | sed -ne '/^\w\+=/!q; p;'; }
La diferencia es que esta solución SE DETIENE después del primer informe no variable, por ejemplo, la primera función informada por set
Por cierto: El problema de "Tino" está resuelto. Aunque POSIX está desactivado y las funciones son informadas por set
, la sed ...
parte de la solución solo permite informes variables (por ejemplo, VAR=VALUE
líneas). En particular, noA2
aparece de forma falsa en la salida.
+ function a() { echo $'\nA2=B'; }; A0=000; A9=999;
+ SOLUTION | grep '^A[0-9]='
A0=000
A9=999
Y: El problema "DejayClayton" está resuelto (las líneas nuevas incrustadas en los valores de las variables no interrumpen la salida; cada VAR=VALUE
una obtiene una única línea de salida):
+ A1=$'111\nA2=222'; A0=000; A9=999;
+ SOLUTION | grep '^A[0-9]='
A0=000
A1=$'111\nA2=222'
A9=999
NOTA: La solución proporcionada por @DouglasLeeder sufre el problema "DejayClayton" (valores con nuevas líneas incrustadas). A continuación, A1
está mal y A2
no debería mostrarse en absoluto.
$ A1=$'111\nA2=222'; A0=000; A9=999; (set -o posix; set) | grep '^A[0-9]='
A0=000
A1='111
A2=222'
A9=999
FINALMENTE: No creo que la versión sea bash
importante, pero podría. Hice mis pruebas / desarrollo en este:
$ bash --version
GNU bash, version 4.4.12(1)-release (x86_64-pc-msys)
POST-SCRIPT: Dadas algunas de las otras respuestas al OP, me queda <100% seguro de que set
siempre convierte nuevas líneas dentro del valor al \n
que se basa esta solución para evitar el problema "DejayClayton". ¿Quizás ese sea un comportamiento moderno? ¿O una variación en tiempo de compilación? O una set -o
o shopt
ajuste de la opción? Si usted sabe de tales variaciones, por favor añadir un comentario ...
Desde una perspectiva de seguridad, ya sea de @ akostadinov respuesta o @ de JuvenXu respuesta es preferible confiar en la salida no estructurada del set
mando, debido a lo siguiente falla de seguridad potencial:
#!/bin/bash
function doLogic()
{
local COMMAND="${1}"
if ( set -o posix; set | grep -q '^PS1=' )
then
echo 'Script is interactive'
else
echo 'Script is NOT interactive'
fi
}
doLogic 'hello' # Script is NOT interactive
doLogic $'\nPS1=' # Script is interactive
La función anterior se doLogic
utiliza set
para verificar la presencia de una variable PS1
para determinar si el script es interactivo o no (no importa si esta es la mejor manera de lograr ese objetivo; esto es solo un ejemplo).
Sin embargo, la salida de set
no está estructurada, lo que significa que cualquier variable que contenga una nueva línea puede contaminar totalmente los resultados.
Esto, por supuesto, es un riesgo potencial para la seguridad. En su lugar, use el soporte de Bash para la expansión indirecta de nombres de variables o compgen -v
.
Pruebe esto: set | egrep "^\w+="
(con o sin la | less
tubería)
La primera solución propuesta ( set -o posix ; set ) | less
, funciona pero tiene un inconveniente: transmite códigos de control al terminal, por lo que no se visualizan correctamente. Entonces, por ejemplo, si hay (probablemente) una IFS=$' \t\n'
variable, podemos ver:
IFS='
'
…en lugar.
Mi egrep
solución muestra esto (y eventualmente otros similares) correctamente.
bash -c $'a() { echo "\nA=B"; }; unset A; set | egrep "^\w+="' | grep ^A
pantallas incorrectasA=B"
-> ¡Falla!
Probablemente he robado la respuesta hace un tiempo ... de todos modos, un poco diferente como función:
##
# usage source bin/nps-bash-util-funcs
# doEchoVars
doEchoVars(){
# if the tmp dir does not exist
test -z ${tmp_dir} && \
export tmp_dir="$(cd "$(dirname $0)/../../.."; pwd)""/dat/log/.tmp.$$" && \
mkdir -p "$tmp_dir" && \
( set -o posix ; set )| sort >"$tmp_dir/.vars.before"
( set -o posix ; set ) | sort >"$tmp_dir/.vars.after"
cmd="$(comm -3 $tmp_dir/.vars.before $tmp_dir/.vars.after | perl -ne 's#\s+##g;print "\n $_ "' )"
echo -e "$cmd"
}
Una forma sencilla de hacer esto es usar el modo estricto bash configurando las variables de entorno del sistema antes de ejecutar su script y usar diff para ordenar solo las de su script:
# Add this line at the top of your script :
set > /tmp/old_vars.log
# Add this line at the end of your script :
set > /tmp/new_vars.log
# Alternatively you can remove unwanted variables with grep (e.g., passwords) :
set | grep -v "PASSWORD1=\|PASSWORD2=\|PASSWORD3=" > /tmp/new_vars.log
# Now you can compare to sort variables of your script :
diff /tmp/old_vars.log /tmp/new_vars.log | grep "^>" > /tmp/script_vars.log
Ahora puede recuperar variables de su script en /tmp/script_vars.log. ¡O al menos algo basado en eso!
Un poco tarde para la fiesta, pero aquí hay otra sugerencia:
#!/bin/bash
set_before=$( set -o posix; set | sed -e '/^_=*/d' )
# create/set some variables
VARIABLE1=a
VARIABLE2=b
VARIABLE3=c
set_after=$( set -o posix; unset set_before; set | sed -e '/^_=/d' )
diff <(echo "$set_before") <(echo "$set_after") | sed -e 's/^> //' -e '/^[[:digit:]].*/d'
La línea de comando diff + sed pipeline genera todas las variables definidas por script en el formato deseado (como se especifica en la publicación del OP):
VARIABLE1=a
VARIABLE2=b
VARIABLE3=c
-o posix
ahora un diff solo contendrá las variables.