# rm-rf.es | Administración de sistemas

Bitácora personal de un SysAdmin Gnu/Linux, Windows, BSD...

Login Linux: diferencia entre ‘su’ y ‘su -’


su rootYa vimos en otra entrada (/usr/sbin y /sbin no están en $PATH al hacer su) los problemas que nos podía generar hacer login contra un usuario usando únicamente su. Básicamente, la diferencia es que si hacemos su <usuario> a secas “heredaremos” las variables de entorno y lo especificado en los ficheros de inicialización del usuario origen en lugar de recibir los del nuevo. Vamos a ver un ejemplo:

$ whoami
alex
$ echo $PATH
/usr/kerberos/bin:/usr/local/bin:/bin:/usr/bin:/home/alex/bin
$ su
Contraseña:
# whoami
root
# echo $PATH
/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/bin:/bin:/usr/bin:/home/alex/bin

En el anterior ejemplo, pese a convertirme en root, seguía siendo aplicado el $PATH del usuario anterior (alex). En cambio, si ejecutamos su seguido de un guión y el usuario (para ser root no hace falta especificar el usuario) sí que se leerán los ficheros de inicialización de root y por consiguiente se definirá la variable $PATH correctamente:

$ whoami
alex
$ echo $PATH
/usr/kerberos/bin:/usr/local/bin:/bin:/usr/bin:/home/alex/bin
$ su -
Contraseña:
# whoami
root
# echo $PATH
/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin

/usr/sbin y /sbin no están en $PATH al hacer su


Me he encontrado con un problema ante el que el origen parecía un fallo en la variable $PATH que se define al hacer login con un usuario en el sistema. La situación era la siguiente: accedemos por ssh y seguidamente hacemos su para autenticarnos como root. El problema viene en que algunos comandos no se encuentran en el PATH por lo que recibimos errores como estos:

[alex@server  ~$] su
Contraseña:
[root@server alex#] echo $PATH
/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/bin:/bin:/usr/bin:/home/alex/bin

[root@server  ~#] tcpdump
bash: tcpdump: command not found
[root@server   ~#] sendmail
bash: sendmail: command not found

Como podéis ver en la secuencia de comandos, el resultado de la variable $PATH está incompleto, faltan /usr/sbin y /sbin. El correcto sería algo así:

[root@server alex#] echo $PATH
/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin

Probablemente algunos ya hayáis visto donde está el error, y otros no. El fallo es el paso de la autenticación a root, en lugar de su a secas hay que hacerlo con su -<:

$ su -

La aclaración de esto es que el comportamiento por defecto de su es mantener tanto el directorio home del usuario como sus variables de entorno en lugar de adquirir las del nuevo usuario, en este caso root. Así que si queremos adquirir todas las variables de entorno del usuario contra el que hacemos su deberemos especificar el usuario, o en caso de root el guión por lo menos:

$ su - usuario

Bash y SSH: establecer timeout por inactividad


La variable de entorno TMOUT nos permite definir el tiempo que queremos permitir a un usuario permanecer dentro de la shell o sesión SSH sin hacer nada (estado idle o inactivo). Por defecto no hay límite de tiempo por lo que un usuario podrá permanecer de forma indefinida conectado al sistema independientemente de que la sesión se esté utilizando o no.

Para configurar esta variable, simplemente la añadimos dentro de nuestro perfil de variables/configuraciones de bash ~/.bash_profile o ~/.bashrc. Conviene configurarla como read only para evitar que el propio usuario pueda modificarla:

# Establecemos en 2 minutos (120 segundos) el Timeout para la sesión bash/ssh
TMOUT=120
readonly TMOUT

Refrescamos la shell o entramos y salimos para que sea efectivo:

$ bash

También podemos establecerla a tiempo real mediante export:

$ export TMOUT=120

A partir de ahora, si dejamos la shell abierta durante 2 minutos sin realizar ninguna tarea automáticamente nos desconectará de la sesión:

$ timed out waiting for input: auto-logout

Comando DATE en bash: sumar y restar años, días o meses a la fecha actual


El comando date, a través del parámetro

-d, --date=STRING

permite mostrar y calcular la fecha distinta a la actual a partir de la suma o resta de X años, meses, días, minutos o segundos. Esto es útil cuando queremos por ejemplo añadir o restar 7 días a la fecha actual. Vamos a ver unos cuantos ejemplos:

Sumar 7 días a la fecha actual y mostrarlo en formato estándar:

$ date --date='+7 day'
vie may 13 17:40:47 CEST 2011

Restar 7 días a la fecha actual y mostrarlo en formato timestamp:

$ date +%s --date='-7 day'
1304091656

Sumar un año a la fecha actual con formato de fecha y hora:

$ date +%c --date='+1 year'
dom 06 may 2012 17:41:53 CEST

Restar dos meses a la fecha actual:

$ date --date='-2 month'
dom mar  6 16:42:48 CET 2011

Y así muchos más ejemplos. Seguro que os resulta muy útil dentro de scripts en bash por ejemplo.

Variables locales y globales en BASH


bashLa shell BASH nos permite utilizar dos tipos de variables, las locales y globales (environment variables). Básicamente, la diferencia entre ambas es que la variable local tiene valor únicamente dentro de nuestra shell, es decir de nuestra sesión. Ningún otro usuario tiene acceso a ella. Por el contrario, las variables globales se establecen para todas las shells., hay que aclarar este último concepto, las variables globales se heredarán desde esta shell a las que se creen a partir de ella (sub-shell o proceso hijo “child” ).

Crear variables locales en bash

Crear una variable local es extremadamente sencillo. En bash por estándar el nombre que asignemos a la variable irá en mayúscula, seguido de un “=” y el valor de la variable, ejemplo:

$ VAR1=prueba_variable_1

La variable ya puede ser usada en cualquier momento desde nuestra shell. A la hora de usar la variable una vez declarada le anteponemos el $, pero no cuando la creamos, ejemplo:

$ echo $VAR1
prueba_variable_1

En todo momento podemos listar las variables establecidas en la shell, para ello ejecutamos el comando

set

:

$ set
BASH=/bin/bash
BASH_ARGC=()
BASH_ARGV=()
BASH_COMPLETION=/etc/bash_completion
BASH_COMPLETION_DIR=/etc/bash_completion.d
BASH_LINENO=()
BASH_SOURCE=()
BASH_VERSINFO=([0]="3" [1]="2" [2]="48" [3]="1" [4]="release" [5]="i486-pc-linux
-gnu")
...
...
...

El listado es muy amplio, así que acotamos la búsqueda a la variable que nos interesa:

$ set | grep ^VAR1
VAR1=prueba_variable_1

Para eliminar la variable utilizamos

unset

seguido del nombre asignado a la variable:

$ unset VAR1

Crear variables de entorno o globales en bash

La sintaxis es distinta, para crear una variable de entorno usaremos

export

seguido de la variable:

$ export VAR2=prueba_variable_2

Al igual que con las variables locales, podemos utilizarla instantáneamente, además en este caso la variable existirá también si abrimos nuevas shells (con el comando bash por ejemplo), mientras que en las variables locales se perdería:

$ echo $VAR2
prueba_variable_2
$ bash
$ echo $VAR2
prueba_variable_2

A la hora de listar las variables de entorno tenemos tres posibilidades, usar

set

como con las locales o

export

o

env

:

$ env | grep ^VAR2
VAR2=prueba_variable_2

$ export | grep VAR2
declare -x VAR2="prueba_variable_2"

$ set | grep ^VAR2
VAR2=prueba_variable_2

Para eliminar la variable hacemos igual que en las locales, unset:

$ unset $VAR2

Normalmente las variables de entorno se definen en el momento que se hace login, a través del fichero .bashrc por ejemplo. Algunas variables de entorno predefinidas en bash son DISPLAY, HOME, PATH, PS1, PWD, SHELL o TERM.

Gestión de trabajos en BASH (jobs, fg, bg, &…)


Hoy vamos a ver el modo de gestionar trabajos, procesos o aplicaciones que corren dentro de un sistema Linux/Unix. El objetivo es aprender a poner un proceso que se está ejecutando en segundo plano, suspenderlo, volver a ponerlo en primer plano, reactivarlo, etc.

Ejecutar un trabajo/proceso en segundo plano

Para ejecutar algo en segundo plano, debemos utilizar el carácter & y colocarlo tras el comando o proceso a ejecutar:

$ top &

Os recomiendo también revisar esta entrada sobre el comando nohup.

Visualizar los procesos que se encuentran en segundo plano

Para obtener un listado de los procesos que están ejecutándose en segundo plano utilizaremos el comando

bg

(background). La salida del mismo nos indicará cada uno de los procesos con su número de trabajo asignado entre corchetes.

$ bg
[1]+ top &

Traer a primer plano los procesos que se encuentran en segundo plano

Para ello utilizaremos el comando

fg

(foreground) junto con el ID del trabajo anteponiéndole %:

$ fg %1

Suspender un proceso que tenemos corriendo en primer plano

Si estamos ejecutando un trabajo en pantalla/terminal y queremos suspenderlo colocarlo en segundo plano utilizaremos la combinación de teclas Ctrl + Z. Automáticamente nos asignará el ID de trabajo para poder gestionarlo posteriormente:

top - 21:20:57 up 33 min,  2 users,  load average: 0.99, 0.98, 0.81
Tasks: 112 total,   1 running, 111 sleeping,   0 stopped,   0 zombie
Cpu(s): 23.0%us,  4.7%sy,  0.0%ni, 70.5%id,  1.6%wa,  0.1%hi,  0.0%si,  0.0%st
Mem:   2052640k total,   948528k used,  1104112k free,    55876k buffers
Swap:  1951888k total,        0k used,  1951888k free,   461444k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                                                                                  

  776 root      15  -5     0    0    0 S    0  0.0   0:00.02 kjournald2                                                                                                               

[1]+  Stopped                 top

Para volver a arrancarlo en primer plano después:

$ fg %1

Y para ponerlo en segundo plano:

$ bg %1

Esto es realmente útil en casos como por ejemplo, estamos ejecutando un script que se demora más de lo esperado y necesitamos ejecutarlo sin necesidad de una terminal, lo dejamos en segundo plano y seguirá corriendo sin necesidad de ningún entorno visual. También si solo disponemos de una única terminal y necesitamos realizar varias tareas simultaneamente.

Visualizar los trabajos en primer plano, suspendidos, en segundo plano

El comando

jobs

nos permite visualizar un listado de los trabajos en el sistema junto con su estado e identificador:

$ jobs
[1]   Stopped                 top
[2]-  Stopped                 top
[3]+  Stopped                 vim

Un resumen práctico sería el siguiente. Arrancamos un programa (por ejemplo thunderbird) desde línea de comandos:

$ thunderbird

Ocurre que necesitamos pararlo temporalmente. En la terminal desde la que lo hemos lanzado presionamos Ctrl + Z.

Ahora el programa está parado a la espera de ser reactivado cuando queramos:

$ thunderbird
^Z
[1]+  Stopped                 thunderbird
$ jobs
[1]+  Stopped                 thunderbird

Podemos arrancarlo de nuevo pero en segundo plano:

$ bg %1
[1]+ thunderbird &

O en primer plano:

$ fg %1

Recordad que es interesante revisar la ayuda (páginas man y –help) de los comandos para obtener información sobre su utilización y las posibilidades que nos ofrece.

Automatizar tareas FTP dentro de un script en BASH


La automatización de tareas vía FTP dentro de un script, puede resultar muy útil para scripts de copias de seguridad por ejemplo. Vamos a ver la forma de hacerlo y las posibilidades que nos ofrece.

La sintaxis básica para hacer la llamada a FTP dentro de un script en bash es la siguiente:

ftp -inv direccion_ip<<FINFTP
comando1
comando2
comando3
FINFTP

Comenzamos explicando los parámetros que pasamos al binario FTP,

i

sirve para desactivar el prompt interactivo,

n

sirve para impedir que se use la auto-autenticación, podéis quitarlo si vais a usar el acceso automático a través de .netrc, finalmente

v

es para verbose.

Posteriormente, dentro de la llamada a FTP ya se trata de añadir los comandos que cada uno necesite, en el siguiente ejemplo nos conectamos con usuario test y clave t3st al ftp 192.168.0.100 y subimos dos ficheros desde la carpeta local /home/local hacia la carpeta remota /.

#!/bin/bash
ftp -inv 192.168.0.100<<FINFTP
       user test t3st
       binary
       lcd /home/local
       cd /home/download
       put fichero1.txt
       put fichero2.txt
       bye
FINFTP

Codificar y descodificar Base64 desde BASH


El comando base64 permite codificar y descodificar cadenas de caracteres desde línea de comandos GNU/Linux, en este caso desde BASH.

Para codificar el contenido de un fichero utilizaremos la siguiente sintaxis, utilizaremos el fichero test.txt que contiene la cadena “esto es una prueba”:

$ base64 test.txt
ZXN0byBlcyB1bmEgcHJ1ZWJhCg==

Para descodificarlo utilizamos la siguiente sintaxis, en este caso el fichero de texto contiene la cadena encriptada “ZXN0byBlcyB1bmEgcHJ1ZWJhCg==”:

$ base64 -d test.txt
esto es una prueba

Si queremos codificar o descodificar directamente la cadena de texto, la mandamos a salida estandar y luego la codificamos/descodificamos:

$ echo "esto es una prueba" | base64
ZXN0byBlcyB1bmEgcHJ1ZWJhCg==
$ echo "ZXN0byBlcyB1bmEgcHJ1ZWJhCg==" | base64 -d
esto es una prueba