Usos y fundamentos del ODB2


¿Ha notado que la luz indicadora de mal funcionamiento aparece en su tablero de instrumentos? Pues ese mensaje  le dice que hay un problema y que debe visitar a un mecánico. En el pasado, esto solo indicaría un problema, ¡pero hoy en dia gracias al interfaz ODB2  hay  más orientación pues  su mecánico utilizará un escáner OBD2 para identificar la causa, para lo cual  conectará el lector OBD2 al conector OBD2 de 16 pines cerca de la rueda del conductor y  esto le permitirá leer los códigos OBD2 AKA Códigos de diagnóstico de problemas (DTC) y comprender el problema. ¡Sin desarmar el coche!

El diagnóstico a bordo (OBD) es el sistema de autodiagnóstico incorporado en la mayoria de los  vehículos modernos indicando cuando hay un error a través de la ‘luz indicadora de mal funcionamiento’ permitiendo a un mecánico (o a usted) solucionar problemas al escanear códigos de diagnóstico de problemas (DTC) .OBD2 se ejecuta en bus CAN en la mayoría de los vehículos hoy y  lo mas importante; se puede acceder al sistema OBD2 a través de un conector OBD2 de 16 clavijas que se encuentra a 0,61 m del volante lo cual dará  muchas posibilidades para un sinfin de aplicaciones

 

 

 

Historia

El sistema se origina en California, donde la Junta de Recursos del Aire de California(CARB) que requirió en todos los automoviles nuevos a partir de 1991 para fines de control de emisiones determimando  que todos los automóviles a gasolina contaran con OBD (On Board Diagnostics), el cual  controlara los límites máximos de emisiones y además un autocontrol, el On Board Diagnostics de componentes relevantes de las emisiones de gas a través de dispositivos de mando electrónicos. Ademas ,para que el conductor detectese  un mal funcionamiento del OBD se impuso la obligación de tener una lámpara que indique fallos (MIL – Malfunction Indicator Lamp).

Medidas más estrictas en los límites de emisiones en 1996 llevó a la creación del OBD II.  El estándar OBD2 fue recomendado por la Society of Automotive Engineers (SAE) y los DTC estandarizados y el conector OBD en todos los fabricantes ( SAE j1962 )  y desde 1996 el OBD II es un requisito legal para automóviles nuevos en Estados Unidos. 

En Europa se introdujo el OBD ajustándose al OBD-II americano y con base en esta regla americana se impuso en los noventa la inclusión de sistemas de diagnóstico también para los automóviles destinados al mercado europeo,mas concretamente según la Directiva 98/69EG, los automóviles a gasolina del año 2000 en adelante, los diésel de 2003 en adelante, y los camiones de 2005 en adelante tienen que estar provistos de un OBD. La interfaz estándar del OBD-II no solamente es utilizada por el fabricante para sus funciones avanzadas de diagnóstico sino también por aquellos que van más allá de lo que la ley exige.

 

A partir de ahí, el estándar OBD2 se implementó paso a paso :

  • 1996: OBD2 se hizo obligatorio en Estados Unidos para automóviles y camiones ligeros.
  • 2001: Requerido en la UE para automóviles de gasolina.
  • 2003: Requerido en la UE también para autos diesel (EOBD)
  • 2005: OBD2 fue requerido en los EE. UU. Para vehículos de servicio mediano
  • 2008: los autos de los EE . UU. Debían usar ISO 15765-4 (una variante de CAN) como base para OBD2
  • 2010: Finalmente, se requirió OBD2 en vehículos pesados ​​de EE. UU.

¿Mi coche tiene OBD2?

La siguiente etapa planeada es el OBD-III, en el que los propios automóviles se comunican con las autoridades si se produce un empeoramiento de las emisiones de gases nocivos mientras está en marcha. Si esto sucede, se pedirá a través de una tarjeta indicativa, que se corrijan los defectos

Interfaz de diagnóstico OBD1

OBD I fue la primera regulación de OBD que obligaba a los productores a instalar un sistema de monitorización de algunos de los componentes controladores de emisiones en automóviles. Obligatorios en todos los vehículos a partir de 1991, sin embargo fue creada esta tecnología en 1983 así como implementada en algunos vehículos americanos en 1987 y 1988, los sistemas de OBD I no eran tan efectivos porque solamente monitorizaban algunos de los componentes relacionados con las emisiones, y no eran calibrados para un nivel específico de emisiones.

OBD II

OBD II es la segunda generación del sistema de diagnóstico a bordo, sucesor de OBD I. Alerta al conductor cuando el nivel de las emisiones es 1.5 mayor a las diseñadas. A diferencia de OBD I, OBD II detecta fallos eléctricos, químicos y mecánicos que pueden afectar al nivel de emisiones del vehículo. Por ejemplo, con OBD I, el conductor no se daría cuenta de un fallo químico del catalizador. Con OBD II, los dos sensores de oxígeno, uno antes y el otro después del catalizador, garantizan el buen estado químico del mismo.

El sistema verifica el estado de todos los sensores involucrados en las emisiones, como por ejemplo la inyección o la entrada de aire al motor. Cuando algo falla, el sistema se encarga automáticamente de informar al conductor encendiendo una luz indicadora de fallo (Malfunction Indication Lamp (MIL), también conocida como Check Engine o Service Engine Soon).

Para ofrecer la máxima información posible para el mecánico, guarda un registro del fallo y las condiciones en que ocurrió. Cada fallo tiene un código asignado. El mecánico puede leer los registros con un dispositivo que envía comandos al sistema OBD II llamados PID (Parameter ID).

Generalmente el conector OBD II suele encontrarse en la zona de los pies del conductor, consola central o debajo del asiento del copiloto.

Actualmente se puede conectar con la máquina de diagnosis de diferentes maneras, mediante Bluetooth, WiFi, USB, cayendo en desuso el protocolo de conexión por el puerto serie (RS232). Este enlace, unido a un software ejecutándose desde un ordenador o un terminal móvil permite la monitorización en tiempo real de códigos de error y diversos parámetros directamente de la centralita del motor tales como las revoluciones del motor, el consumo de combustible en tiempo real (sin que el automóvil lleve equipado ordenador de a bordo) o la temperatura del aceite, entre muchos otros parámetros dependiendo del modelo. El controlador ELM327 es el más extendido para establecer dichos enlaces entre la centralita del motor y el dispositivo con el software instalado.

Existen controladores más avanzados, clones del software original de los fabricantes, que permiten adicionalmente programar ciertas configuraciones del vehículo, como el equipamiento y la realización de testeos. OP-COM, VAG-COM, etc son algunos ejemplos.

EOBD

EOBD es la abreviatura de European On Board Diagnostics (Diagnóstico de a Bordo Europeo), la variación europea de OBD II. Una de las diferencias es que no se monitorizan las evaporaciones del depósito de combustible. Sin embargo, EOBD es un sistema mucho más sofisticado que OBD II ya que usa «mapas» de las entradas a los sensores basados en las condiciones de operación del motor, y los componentes se adaptan al sistema calibrándose empíricamente. Esto significa que los repuestos necesitan ser de alta calidad y específicos para el vehículo y modelo.

JOBD

JOBD es una versión de OBD-II para los vehículos vendidos en Japón.

 

 

Conector SAE-J1962

El conector OBD2 le permite acceder fácilmente a los datos de su automóvil, pero ¿qué es realmente?

El estándar OBD2 (SAE J1962) especifica dos tipos de conector hembra de 16 pines OBD2 (A y B).

A continuación se muestra un ejemplo de un conector pin OBD2 tipo A (también conocido como conector de enlace de datos, DLC):

 

pin descripción
2
SAE J1850 Bus +
4
Chasis
5
Señal de Masa (signal Ground)
6
ISO 15765-4 CAN BUS High
7
ISO9141 K Line
10
SAE J1850 Bus –
14
ISO 15765-4 CAN bus Low
15
ISO9141 L-Line
16
+12V  procedentes de  la bateria  del vehiculo   (siempre  activo)

Los pines 1,3,8,9,11,13  no se usan

El DLC OBD2 debe ubicarse en el compartimiento del pasajero o del conductor en el área delimitada por el extremo del conductor del panel de instrumentos a 300 mm (~ 1 pie) más allá de la línea central del vehículo, acoplado al panel de instrumentos y de fácil acceso desde el asiento del conductor . La ubicación preferida es entre la columna de dirección y la línea central del vehículo. 

 

De acuerdo con la norma SAE J1962, el DLC tipo A «debe estar ubicado en el compartimiento del pasajero o del conductor en el área delimitada por el extremo del conductor del panel de instrumentos a 300 mm (~ 1 pie) más allá de la línea central del vehículo, unido al panel de instrumentos y fácil para acceder desde el asiento del conductor. La ubicación preferida es entre la columna de dirección y la línea central del vehículo «. El DLC tipo B «se ubicará en el compartimiento del pasajero o del conductor en el área delimitada por el extremo del conductor del panel de instrumentos, incluido el lado exterior, y una línea imaginada de 750 mm (~ 2.5 pies) más allá de la línea central del vehículo. Será conectado al panel de instrumentos y de fácil acceso desde el asiento del conductor o desde el asiento del copiloto o desde el exterior. El conector del vehículo debe montarse para facilitar el acoplamiento y el desacoplamiento «.

 


El conector OBD2 está cerca del volante, pero puede estar oculto detrás de las cubiertas / panelesNo todos los conectores macho se adaptan a todos los enchufes hembra OBD2; verifique el tipo y las clavijas OBDEl pin 16 suministra energía a través de la batería del automóvil, a menudo también cuando el encendido está apagadoLos pines 6 (CAN-H) y 14 (CAN-L) son más relevantes ya que CAN (ISO 15765-4) es estándar en la mayoría de los automóviles modernos (incl. EVs)

 casi todos los vehículos modernos cuentan  con una interfaz OBD2 / EUOBD.  Para conocer si su  vehículo  lo es  puede abrir el capó del motor y debería encontrar una pegatina, si la etiqueta tiene la letra “OBDII CERTIFIED”, significa que puede instalar el HUD.   No obstante , aunque el vehículo no cuente con esta pegatina, lo normal es que si es un vehículo del 2010  en adelante , esta característica la soporte. 

ond2.PNG

Para verificar el conector de diagnóstico del vehículo debajo del volante, puede encontrar la  toma de 16 pins del vehículo.

figura2
IMG_20180120_162125[1].jpg

 

 

 

¿Por qué debería preocuparse por los datos OBD2?

Los mecánicos obviamente se preocupan por los DTC (quizás usted también lo haga), mientras que las entidades reguladoras lo necesitan para controlar las emisiones.

Pero OBD2 en realidad admite una amplia gama de ID de parámetros estándar (PID) que se pueden registrar en la mayoría de los automóviles lo cual  significa que, por ejemplo, puede obtener datos OBD2 en vivo legibles para el ser humano desde su automóvil en velocidad, RPM, posición del acelerador y más, datos que podemos vusualizar  bien en un HUD  en el parabrisas o  usando  una app movil( ODDB2 doctor por ejemplo)   por medio de un  dispositivo  odb2 con bluettoth .

 

 
OBD2 es la forma más sencilla de obtener datos básicos legibles por personas desde su vehículo.

Pero, ¿no puede obtener estos datos directamente del bus CAN? No necesariamente, ya que los datos CAN sin procesar en la mayoría de los autos son propietarios; para obtener más información, expanda lo siguiente:Decodificación – OBD2 vs CAN Bus Data

Wikipedia tiene un excelente artículo sobre los PID OBD2 estandarizados. También existe una herramienta de conversión en línea OBD2 donde puede ingresar un mensaje para devolver la información PID y los datos convertidos.

OBD2 PIDS Y MENSAJES EXPLICADOS

Para comenzar a grabar datos OBD2, es útil comprender los conceptos básicos de la estructura del mensaje .

En términos simplificados, un mensaje OBD2 se compone de un identificador y datos .

Además, los datos se dividen en modo, PID y bytes de datos Ah, Bh, Ch, Dh (en valores hexadecimales) – cf. la figura de abajo.

OBD2 PIDs Desglose de la estructura del mensaje OBD-ii explicado

Un ejemplo de un mensaje CAN de solicitud / respuesta para el PID ‘Velocidad del vehículo’ con un valor de 50 km / h puede verse así:

Solicitud: 7DF 02 01 0D 55 55 55 55 55 
Respuesta: 7E8 03 41 0D 32 aa aa aa aa aa

(Aquí el 32 es el valor hexadecimal de 50) .

 

A continuación, se explica cada parte del mensaje OBD2:

  • IDENTIFICADOR: Para los mensajes OBD2, el identificador es estándar de 11 bits y se utiliza para distinguir entre » mensajes de solicitud » (ID 7DF) y » mensajes de respuesta » (ID 7E8 a 7EF). Tenga en cuenta que 7E8 normalmente será donde el motor principal o la ECU responda.
  • LONGITUD: Esto simplemente refleja la longitud en número de bytes de los datos restantes (03 a 06). Para el ejemplo de Velocidad del vehículo, es 02 para la solicitud (ya que solo siguen 01 y 0D), mientras que para la respuesta es 03, ya que siguen 41, 0D y 32.
  • MODO: Para solicitudes, esto será entre 01-0A. Para las respuestas, el 0 se reemplaza por 4 (es decir, 41, 42, …, 4A). Hay 10 modoscomo se describe en el estándar SAE J1979 OBD2. El Modo 1 muestra los Datos actuales y, por ejemplo, se usa para observar la velocidad del vehículo en tiempo real, RPM, etc. Otros modos se utilizan para, por ejemplo, mostrar o borrar códigos de diagnóstico de problemas almacenados y mostrar datos de imágenes congeladas.
  • PID: para cada modo, existe una lista de PID OBD2 estándar, por ejemplo, en el Modo 01, PID 0D es la Velocidad del vehículo Cada PID tiene una descripción y algunos tienen una fórmula de conversión / mínimo / máximo especificada. La fórmula para la velocidad es, por ejemplo, simplemente A, lo que significa que el byte de datos Ah (que está en HEX) se convierte a decimal para obtener el valor convertido en km / h (es decir, 32 se convierte en 50 km / h arriba). Para, por ejemplo, RPM (PID 0C), la fórmula es (256 * A + B) / 4. 
  • > Ah, Bh, Ch, Dh: Estos son los bytes de datos en HEX , que deben convertirse a formato decimal antes de que se usen en los cálculos de la fórmula PID. Tenga en cuenta que el último byte de datos (después de Dh) no se utiliza.

 

¿CÓMO REGISTRAR DATOS OBD2?

El registro de datos OBD2 funciona de la siguiente manera:

  • Conectar un escáner OBD2 o un registrador de datos OBD2 al conector OBD2 de 16 pines.
  • A través de la herramienta, usted ingresa “ mensajes de solicitud ” (consultas) transmitidos a través del bus CAN
  • Las ECU relevantes reaccionan y envían » mensajes de respuesta » a través del bus CAN

Esto es importante:

Esto significa que no verá datos OBD2 si simplemente conecta un registrador o interfaz «pasivo» a su automóvil.(Sin embargo, esto produciría datos CAN sin procesar ya que se «difunde»).

Para registrar mensajes de respuesta OBD2 , su registrador de datos OBD2 debe poder enviar los mensajes de solicitud.

Solicitud de datos OBD2 de Car Response PID Velocidad del vehículo OBD-II

 

 

¿QUÉ GRABADORA OBD2 NECESITO?

Existen varias opciones: a continuación, describimos las principales categorías de analizadores OBD2 :

ESCÁNERES OBD2 / LECTORES DE CÓDIGO: se utilizan principalmente en la lectura / eliminación estática de códigos de diagnóstico de problemas. Por ejemplo, los mecánicos los utilizan para buscar el problema subyacente detrás de una lámpara indicadora de mal funcionamiento (MIL). 

REGISTRADORES DE DATOS OBD2: se utilizan para registrar datos OBD2 de un automóvil a lo largo del tiempo, por ejemplo, en una tarjeta SD ; esto puede ser útil para el análisis posterior y, por ejemplo, para analizar patrones, correlaciones, etc. Además, para fines de diagnóstico / optimización, un registrador de datos proporciona un cuadro «vista de patrones de datos antes y después de que un código de diagnóstico se haya activado.

Los registradores de datos OBD2 con Bluetooth o WiFi también se utilizan, por ejemplo , en la gestión de la flota de vehículos para mejorar la eficiencia del combustible, evitar la conducción insegura y permitir diagnósticos remotos proactivos a través de los parámetros compatibles con OBD2.

INTERFACES DE DATOS OBD2: Se utilizan para proporcionar datos en tiempo real en tiempo real sobre varios parámetros OBD2. Las aplicaciones pueden incluir pantallas / aplicaciones visuales que guían al conductor en cuanto a eficiencia de combustible o rendimiento, o como un chequeo de estado en vivo.

Las interfaces OBD2 más avanzadas también se pueden usar para transmitir datos OBD2 junto con datos de bus CAN patentados, que pueden ser útiles para el rastreo de CAN y el pirateo de automóviles .

Además, también existen híbridos : la serie CLX000 puede, por ejemplo, actuar como un registrador de datos y una interfaz OBD2 .

Shell scripting :funciones ,subshells y variables de entorno


Bash , c-shell  o simplemente shell scripting es  un lenguaje de script  creado a fines de la década de 1980 por un programador llamado Brian Fox, que trabajaba para la Free Software Foundation . Fue pensado como una alternativa de software libre para el shell Bourne (de hecho, su nombre es un acrónimo de Bourne Again SHell ), e incorpora todas las características de ese shell, así como nuevas características como la aritmética de enteros y el control de trabajo

Bash es un “shell de Unix”, es decir  una interfaz de línea de comandos para interactuar con el sistema operativo por lo que está ampliamente disponible, siendo el shell predeterminado en muchas distribuciones de GNU / Linux y en Mac OSX, con puertos existentes para muchos otros sistemas.

En post anteriores hemos hablado en una primera aproximación  al lenguaje c-sheall  con el primer ejemplo famoso de  Hello world y avanzando comandos ,tuberías ,variables ,parámetros y salidas posibles y en un segundo post  sobre el  uso de las Tuberías , sustitución de comandos,operadores ,asignación de variables ,Bucles , literales , variables   y aritmética no entera

En este  post  vamos  a continuar  avanzando en el conocimiento de este lenguaje con el uso de las funciones, subshells  y las  variables de entorno

close up code coding computer

 

 

 

Funciones de shell 

Una función de shell es un tipo especial de variable que es esencialmente un script dentro de otro script. Gracias a estas funciones c-shell  nos permite agrupar una secuencia de comandos en un solo comando con nombre, lo cual es particularmente útil si la secuencia de comandos necesita ejecutarse desde muchos lugares dentro del script  .

Como una función de shell puede incluso consistir en un solo comando; esto puede ser útil si el comando es particularmente complicado, o si su significado no sería inmediatamente obvio para un lector,es  decir, las funciones de shell pueden servir para dos propósitos:

  • pueden guardar la escritura
  • Pueden permitir un código más legible mediante la creación de comandos con nombres intuitivos

Como ejemplo considere la siguiente secuencia de comandos:

#! / bin / bash
# Uso: get_password VARNAME 
# Le pide al usuario una contraseña y lo guarda como $ VARNAME. 
# Devuelve un estado de salida distinto de cero si la entrada estándar no es un terminal, o si el 
comando # "leer" devuelve un estado de salida distinto de cero. 
get_password ()  { 
  si  [[ -t 0  ]]  ;  then
    read -r -p 'Contraseña:' -s "  $ 1  "  &&  echo 
  else 
    return  1
   fi
 }

get_password PASSWORD &&  echo  "  $ PASSWORD  "

El script anterior crea una función de shell llamada get_password que le pide al usuario que escriba una contraseña y almacena el resultado en una variable específica. Luego ejecuta get_password PASSWORD para almacenar la contraseña como $ PASSWORD ; y por último, si la llamada a get_password tuvo éxito (según lo determinado por su estado de salida), la contraseña recuperada se imprime en la salida estándar (que obviamente no es un uso realista pues  el objetivo aquí es simplemente demostrar el comportamiento de get_password ).

La función get_password no hace nada que no se pueda hacer sin una función de shell, pero el resultado es mucho más legible. La función invoca la lectura de comando incorporada (que lee una línea de entrada del usuario y la guarda en una o más variables) con varias opciones con las que la mayoría de los programadores de Bash no estarán familiarizados:

  • La opción -r desactiva un significado especial para el carácter de barra diagonal inversa;
  • la opción -p hace que aparezca un mensaje específico, en este caso Contraseña:, al principio de la línea;
  • la opción -s evita que se muestre la contraseña a medida que el usuario lo escribe. Desde la -s la opción también evita que se muestre la nueva línea del usuario,

El comando echo proporciona una nueva línea y además, la función usa la expresión condicional -t 0 para asegurarse de que la entrada del script proviene de un terminal (una consola) y no de una archivo o de otro programa que no sabría que se está solicitando una contraseña. (Esta última característica es discutible; dependiendo de la funcionalidad general del script,pues  puede ser mejor aceptar una contraseña de entrada estándar independientemente de su origen, suponiendo que la fuente se diseñó teniendo en cuenta el script). El punto general es que darle un nombre a la secuencia de comandos – get_password – hace que sea mucho más fácil para un programador saber qué hace.

Dentro de una función de shell, los parámetros posicionales$ 1 , $ 2 , etc., así como $ @ , $ * y $ # ) se refieren a los argumentos con los que se llamó a la función, no a los argumentos del script que contiene la función. Si se necesitan estos últimos, entonces deben pasarse explícitamente a la función, usando "$ @" . (incluso entonces, shift y set solo afectarán a los parámetros posicionales dentro de la función, no a los de la persona que llama).

Una llamada de función devuelve un estado de salida, al igual que un script (o casi cualquier comando). Para especificar explícitamente un estado de salida, use el comando return , que finaliza la llamada a la función y devuelve el estado de salida especificado. (El comando de salida no se puede usar para esto, ya que terminaría la secuencia de comandos completa, como si se llamara desde fuera de una función). Si no se especifica ningún estado de salida, ya sea porque no se da ningún argumento al comando de devolución o porque se llega al final de la función sin haber ejecutado un comando de retorno , a función devolverá el estado de salida del último comando que se ejecutó.

Incidentalmente, cualquiera de las funciones o () pueden omitirse de una declaración de función, pero al menos una debe estar presente. En lugar de , muchos programadores escriben  de manera similar, la notación {...} que no es exactamente necesaria y no es específica de las funciones; es simplemente una notación para agrupar una secuencia de comandos en un solo comando compuesto.

El cuerpo de una función debe ser un comando compuesto, como un bloque {…} o una instrucción if ; {…} Es la opción convencional, incluso cuando todo lo que contiene es un comando compuesto único y, por lo tanto, teóricamente podría prescindirse de él.function get_password ( )get_password ()

Subshells 

En Bash, uno o más comandos se pueden envolver entre paréntesis, lo que hace que esos comandos se ejecuten en una «subshell»(también hay algunas formas en que se pueden crear subshells implícitamente) Un subshell recibe una copia del «entorno de ejecución» del contexto circundante, que incluye cualquier variable, entre otras cosas; pero cualquier cambio que haga a subshell al entorno de ejecución no se vuelve a copiar cuando se completa la subshell.

Así, por ejemplo, este script: #! / bin / bash

foo  = barra
 echo  "  $ foo  "  # imprime 'barra'

# subshell:
 (
  echo  "  $ foo  "  # imprime 'barra' - la subshell hereda las variables de sus padres 
  baz  = bip
   echo  "  $ baz  "  # imprime 'bip' - la subshell puede crear sus propias variables 
  foo  = foo
   echo  "  $ foo  "  # imprime ' foo '- la subshell puede modificar variables heredadas
 )

echo  "  $ baz  "  # no imprime nada (solo una nueva línea) - se pierden las nuevas variables de la subshell 
echo  "  $ foo  "  # imprime 'barra' - los cambios de la subshell a las variables antiguas se pierden

La ejecución imprimirá esta salida:

bar

bar

bip

foo

bar

Si necesitase llamar a una función que modifica una o más variables, pero en realidad no desea que esas variables se modifiquen, puede ajustar la llamada a la función entre paréntesis, para que tenga lugar en una subshell. Esto «aislará» las modificaciones y evitará que afecten el entorno de ejecución circundante.Dicho esto: cuando sea posible, es mejor escribir funciones de tal manera que este problema no se presente para comenzar, pues la palabra clave local puede ayudar con esto.

Lo mismo ocurre con las definiciones de funciones; al igual que una variable regular, una función definida dentro de una subshell no es visible fuera de la subshell.

Una subshell también delimita los cambios a otros aspectos del entorno de ejecución; en particular, el comando cd («cambiar directorio») solo afecta a la subshell. Así, por ejemplo, este script:

  #! / bin / bash

cd /
 pwd  # imprime '/'

# subshell:
 (
  pwd  # prints '/' - la subshell hereda el directorio de trabajo 
  cd home
   pwd  # prints '/ home' - la subshell puede cambiar el directorio de trabajo 
)  # end of subshell

pwd  # prints '/': los cambios de la subshell en el directorio de trabajo se pierden

imprime esto:

/ / /casa /

Si su script necesita cambiar el directorio de trabajo antes de ejecutar un comando dado, es una buena idea usar una subshell si es posible,. de lo contrario, puede resultar difícil hacer un seguimiento del directorio de trabajo al leer un script. Alternativamente, los comandos incorporados pushd y popd se pueden usar para un efecto similar.

 

Una declaración de salida dentro de una subshell termina solo esa subshell. Por ejemplo, este script:

  #! / bin / bash
(  exit  0  )  &&  echo  'subshell successed' 
(  exit 1  )  ||  echo  'subshell failed'

imprime esto:

 subshell tuvo éxito
subshell falló

Al igual que en una secuencia de comandos en su conjunto, exit de los valores predeterminados  devuelve el estado de salida del comando de última ejecución, y una subshell que no tiene una instrucción de salida explícita devolverá el estado de salida del comando de última ejecución.

Variables de entorno

Ya hemos visto que, cuando se llama a un programa, recibe una lista de argumentos que se enumeran explícitamente en la línea de comandos. Lo que no hemos mencionado es que también recibe una lista de pares nombre-valor denominados «variables de entorno».

Diferentes lenguajes de programación ofrecen diferentes formas para que un programa acceda a una variable de entorno; Los programas C pueden usar getenv (" variable_name ") (y / o aceptarlos como un tercer argumento para main ), los programas Perl pueden usar $ ENV {' variable_name '} , los programas Java pueden usar System.getenv (). Get (" variable_name ") , y así sucesivamente.

En Bash, las variables de entorno se convierten simplemente en variables regulares de Bash. Así, por ejemplo, la siguiente secuencia de comandos imprime el valor de la variable de entorno HOME :

#! / bin / bash
echo  "  $ HOME  "

Sin embargo, lo contrario no es cierto: las variables regulares de Bash no se convierten automáticamente en variables de entorno. Así, por ejemplo, este script:

#! / bin / bash
foo  = bar
bash -c 'echo $ foo'

Esto no imprimirá la barra , porque la variable foo no se pasa al comando bash como una variable de entorno. ( De bash -c scripts argumentos ... corre el Bash script de una línea de la escritura ).

Para convertir una variable Bash normal en una variable de entorno, tenemos que «exportarla» al entorno. La siguiente secuencia de comandos hace la impresión de barras :

#! / bin / bash
export  foo  = bar
bash -c 'echo $ foo'

Tenga en cuenta que la exportación no solo crea una variable de entorno; en realidad marca la variable Bash como una variable exportada, y las asignaciones posteriores a la variable Bash también afectarán a la variable de entorno. Ese efecto es ilustrado por este script:

#! / bin / bash
foo  = bar
bash -c 'echo $ foo'  # no imprime nada 
export foo
bash -c 'echo $ foo'  # imprime 'bar' 
foo  = baz
bash -c 'echo $ foo'  # imprime 'baz'

El comando de exportación también se puede usar para eliminar una variable de un entorno, incluyendo la opción -n ; por ejemplo, export -n foodeshace el efecto de export foo. Y múltiples variables pueden ser exportadas o no exportadas en un solo comando, como export foo barexport -n foo bar.

Es importante tener en cuenta que las variables de entorno solo se pasan a un comando; nunca se reciben de vuelta de un comando. En este sentido, son similares a las variables y subshells regulares de Bash. Así, por ejemplo, este comando:

#! / bin / bash
export  foo  = bar
bash -c 'foo = baz'  # no tiene efecto 
echo  "  $ foo  "  # print 'bar'

barra de estampados ; el cambio a $ foo dentro del script de una línea no afecta el proceso que lo invocó. (Sin embargo, podría afectar a cualquier script que fueron llamados a su vez por ese guión.)

Si se desea una variable de entorno dada para un solo comando, se puede usar la sintaxis, con la sintaxis de una asignación de variable (o múltiples asignaciones de variables) que precede a un comando en la misma línea. (Tenga en cuenta que, a pesar de usar la sintaxis de una asignación de variable, esto es muy diferente de una asignación de variable Bash normal, en que la variable se exporta automáticamente al entorno y en que solo existe para el comando. Si desea evitar la confusión de sintaxis similar hacer las cosas diferentes, se puede utilizar la común utilidad Unix env para el mismo efecto que la utilidad también hace que sea posible. eliminar una variable de entorno para un comando – o incluso para eliminar todas las variables de entorno para un comando) Si. $ varvar =value commandya existe, y se desea incluir su valor real en el entorno para un solo comando, que se puede escribir como .var = " $var " command

Aparte: a veces es útil colocar definiciones de variables, o definiciones de funciones, en un script de Bash (por ejemplo, header.sh ) que puede ser llamado por otro script de Bash (por ejemplo, main.sh ). Podemos ver que simplemente invocar ese otro script Bash, como ./header.sh o como bash ./header.sh , no funcionará: las definiciones de variables en header.sh no serán vistas por main.sh , ni siquiera si «exportado» esas definiciones. (Este es un punto de confusión común: exportar las variables de exportación al entorno para que otros procesos puedan verlas, pero solo las ven los procesos secundarios , no los padres.) Sin embargo, podemos usar el comando incorporado Bash («punto») o fuente , que ejecuta un archivo externo casi como si fuera una función de shell. Si header.sh se ve así:

 foo  = función de barra
 baz ()
 {
  echo  "  $ @  "
 }

entonces este script:

#! / bin / bash
. header.sh
baz "  $ foo  "

imprimirá 'barra' .

Alcance 

Ahora hemos visto algunos de los caprichos del alcance variable en Bash.

Para resumir lo que hemos visto hasta ahora:

  • Las variables regulares de Bash están orientadas al shell que las contiene, incluidas las subshells en ese shell.
    • No son visibles para ningún proceso secundario (es decir, para programas externos).
    • Si se crean dentro de una subshell, no son visibles para el shell principal.
    • Si se modifican dentro de una subshell, esas modificaciones no son visibles para el shell principal.
    • Esto también se aplica a las funciones, que en muchos aspectos son similares a las variables regulares de Bash.
  • Las llamadas de función no se ejecutan inherentemente en subshells.
    • Una modificación de variable dentro de una función generalmente es visible para el código que llama a la función.
  • Las variables de Bash que se exportan al entorno tienen un alcance al shell que las contiene, incluidas las subshells o procesos secundarios en ese shell.
    • El comando incorporado de exportación se puede utilizar para exportar una variable al entorno. (También hay otras formas, pero esta es la forma más común).
    • Difieren de las variables no exportadas solo en que son visibles para los procesos secundarios. En particular, todavía no son visibles para shells principales o procesos primarios.
  • Los scripts de Bash externos, como otros programas externos, se ejecutan en procesos secundarios. El o el comando integrado de origen se puede utilizar para ejecutar un script de este tipo internamente, en cuyo caso no se ejecuta de forma inherente en una subshell.

Ademas a  esto añadimos ahora:

  • Las variables de Bash que están localizadas en una función-llamada están sujetas a la función que las contiene, incluyendo cualquier función llamada por esa función.
  • El comando incorporado local se puede usar para localizar una o más variables a una llamada de función, usando la sintaxis local var1 var2o . (también hay otras formas, por ejemplo, el comando declarar incorporado tiene el mismo efecto, pero esta es probablemente la forma más común).local var1 = val1 var2 = val2)
  • Se diferencian de las variables no localizadas en que desaparecen cuando finaliza su función-llamada. En particular, todavía son visibles para subshells y llamadas de función hijo. Además, al igual que las variables no localizadas, se pueden exportar al entorno para que también las vean los procesos secundarios.

En efecto, usar local para localizar una variable en una función-llamada es como poner la función-llamada en una subshell, excepto que solo afecta a una variable; otras variables pueden dejarse sin ser «locales».

 

Una variable que se establece dentro de una función (ya sea mediante asignación o mediante un comando for-loop u otro comando incorporado) debe marcarse como «local» utilizando el comando incorporado local , para evitar que se afecte accidentalmente el código fuera del función, a menos que se desee específicamente que la persona que llama vea el nuevo valor.

Es importante tener en cuenta que, aunque las variables locales en Bash son muy útiles, no son tan locales como las variables locales en la mayoría de los otros lenguajes de programación, ya que son vistos por llamadas de funciones secundarias. Por ejemplo, este script:

#! / bin / bash

foo  = bar

function f1 ()
 {
  echo  "  $ foo  "
 }

function f2 ()
 {
  local  foo  = baz
  f1 # imprime 'baz'
 }

 f2

En realidad se imprimirá baz en lugar de barra . Esto se debe a que el valor original de $ foo está oculto hasta que devuelve f2 . (En la teoría del lenguaje de programación, una variable como $ foo se dice que tiene un «ámbito dinámico» en lugar de un «ámbito léxico»).

Una diferencia entre local y subshell es que mientras que un subshell toma inicialmente sus variables de su shell principal, una declaración como local foo oculta inmediatamente el valor anterior de $ foo ; es decir, $ foo se desestabiliza localmente. Si se desea inicializar el $ foo local al valor del $ foo existente , debemos especificarlo explícitamente, mediante el uso de una declaración como local foo = "$ foo" .

Cuando una función sale, las variables recuperan los valores que tenían antes de sus declaraciones locales (o simplemente se anulan, si no se habían anulado). Curiosamente, esto significa que un script como este:

 #! / bin / bash

function f ()
 {
  foo  = baz
   local  foo  = bip
 }

foo  = bar
 F
echo  "  $ foo  "

Realmente imprimirá baz : la declaración foo = baz en la función surte efecto antes de que la variable se localice, por lo que el valor baz es lo que se restaura cuando la función regresa.Y dado que local es simplemente un comando ejecutable, una función puede decidir en tiempo de ejecución si localizar una variable dada, por lo que este script:

#! / bin / bash

function f ()
 {
  si  [[  "  $ 1  "  ==  'sí'  ]]  ;  entonces
    Foo
   local fi
  foo  = baz
 }

foo  = bar
f yes # modifica un $ foo localizado, por lo que no tiene ningún efecto 
echo  "  $ foo  "  # imprime 'barra' 
f # modifica el $ foo no localizado, configurándolo en 'baz' 
echo  "  $ foo  "  # imprime 'baz'

Este script en realidad se imprimirá

 bar
baz