Archive

Archive for the ‘Linux’ Category

Adapting Logwatch scripts

February 26th, 2015

Logwatch is a linux tool that usually runs automathicaly through cron parsing through servers logs to creates a customized report analyzing specified areas about the activity of a server.

Recently we got a new server, hereinafter NewServer, and we realized that logwatch was behaving weirdly. We were not getting the desired information as we did on other servers, hereinafter OldServer, so many information given by logwatch in other servers was not present. To make a long story short, it turned out that the /var/log/ files format (secure, syslog,...) was different. We have not identify yet where does this difference come from. It could be because the operative system in NewServer is a newer version, but why the new logwatch is not compatible? Hereinafter, you will find more information about the problem and how did we fixed it.

On one hand the information given by OldServer is shown bellow:

################### Logwatch 7.3 (03/24/06) ####################
 Processing Initiated: Mon Feb 16 04:02:07 2015
  Date Range Processed: yesterday
   ( 2015-Feb-15 )
    Period is day.
 Detail Level of Output: 0
 Type of Output: unformatted
 Logfiles for Host: OldServer
##################################################################
 --------------------- sendmail-largeboxes (large mail spool files) Begin ------------------------
  Large Mailbox threshold: 40MB (41943040 bytes)
  Warning: Large mailbox: bsmuser (51198120)
  Warning: Large mailbox: nagios (51199606)
 ---------------------- sendmail-largeboxes (large mail spool files) End -------------------------
 --------------------- SSHD Begin ------------------------
  Users logging in through sshd:
  user1:
 xxx.xxx.xxx.x.111: 2 times
  user2:
 xxx.xxx.xxx.x.119: 2 times
    Received disconnect:
 11: Bye Bye : 2 Time(s)
 11: Closed due to user request. : 10 Time(s)
 11: disconnected by user : 6 Time(s)
 SFTP subsystem requests: 16 Time(s)
 ---------------------- SSHD End -------------------------
 --------------------- Disk Space Begin ------------------------
   Filesystem            Size  Used Avail Use% Mounted on
    /dev/mapper/VolGroup00-LogVol01
 142G  102G   34G  76% /
  /dev/mapper/VolGroup00-LogVol03
   95G   44G   47G  49% /opt
    /dev/mapper/VolGroup00-LogVol05
 98G   35G   58G  38% /usr
  ---------------------- Disk Space End -------------------------

Therefore, the information given by logwatch on the OldServer was just related with disk space, sshd, pam and mail services. In the other hand, in the information given by the NewServer only disk space is shown while other information was missed:

################### Logwatch 7.3.6 (05/19/07) ####################
 Processing Initiated: Sun Feb 15 03:40:02 2015
 Date Range Processed: yesterday
 ( 2015-Feb-14 )
 Period is day.
 Detail Level of Output: 0
 Type of Output: unformatted
 Logfiles for Host: OldServer
 ##################################################################
   --------------------- Disk Space Begin ------------------------
    Filesystem            Size  Used Avail Use% Mounted on
 /dev/mapper/vg_n0-lv_root
 188G   28G  151G  16% /
 /dev/sda1             485M   81M  379M  18% /boot
 /dev/mapper/vg_n0-lv_opt
 375G  1.2G  355G   1% /opt
 /dev/mapper/vg_n0-lv_usr
 472G   29G  419G   7% /usr
 /dev/mapper/vg_n0-lv_var
 375G   40G  316G  12% /var
  ---------------------- Disk Space End -------------------------
 ###################### Logwatch End #########################

In the sake of clarity we are going to define the variable:

TMP_PATH=/usr/share/logwatch/scripts

We compared the logwatch filters on the different servers (/usr/share/logwatch/scripts), but all were identical, so it did not seem to be a logwatch problem, so, a deeper analysis seemed to be required in order to isolate the problem. Fortunately, this analysis turned to be quite simple because the logwatch’s “debug” option prints almost all the information that processes the command and allows you to execute it
line by line in the command line.

Part of the missed information was that related to ssh, so we choose that for debugging:

logwatch --service sendmail --range=Yesterday --debug 6

This command will print out many information on the screen but the important lines look like this:

cat /var/cache/logwatch/logwatch.aqP9adQd/secure | 
perl $TMP_PATH/shared/onlyservice 'sshd' |
perl $TMP_PATH/shared/removeheaders '' |
perl $TMP_PATH/services/sshd

 

Knowing this, we can now run those commands on the command line. For comparison purposes, we run it on NewServer and OldServer :

cat /var/log/secure | perl $TMP_PATH/shared/onlyservice 'sshd'

The first command provided some information on OldServer but none on NewServer. onlyservice script was identical on both servers, so obviously the problem was the /var/log/secure. It turned out that the format of this file was different on NewServer and that most of the logwatch scripts where not able to deal with it.

NewServer /var/log/secure looks like this:

1424159876 2015 Feb 17 08:57:56 newserver authpriv info sshd Accepted publickey for ...

while OldServer /var/log/secure:

Feb 17 10:33:47 s_sys@oldserver sshd[14805]: Accepted password for ....

Logwatch scripts are able to process the OldServer format, but not NewServer one. The first step then was to modify the $TMP_PATH/shared/onlyservice filter. It turned out to be a perl script and adding the proper regExp fixed the firsts step. In our case we added this line:

elsif ($ThisLine =~ m/^.......... .... ... .. ..:..:.. [ ]*[^ ]* [^ ]* [^ ]* $ServiceName/io){
    print $ThisLine

After this fix, we continue executing the second filter of the command:

cat /var/log/secure | perl $TMP_PATH/shared/onlyservice 'sshd' |
perl $TMP_PATH/shared/removeheaders

In this case the the filter was not removing the corresponding information, again, because the format was different. In this case, we added the following line to $TMP_PATH/shared/ remove headers

ThisLine =~ s/^.......... .... ... .. ..:..:.. .. ........ [^ ]* [^ ]* //;

Finally, we run the last filter from the command line:

cat /var/log/secure | perl $TMP_PATH/shared/onlyservice 'sshd' |
perl $TMP_PATH/shared/removeheaders |
perl $TMP_PATH/services/sshd

And now, we got a nice sshd logwatch output as the one we where getting on OldServer.

Failed logins from:
xxx.xxx.xxx.41 (xxx.xxx.xxx.es): 1 time
Illegal users from:
xxx.xxx.xxx.178 (xxx.xxx.xxx.es): 3 times
Users logging in through sshd:
   user1:
   xxx.xxx.xxx.254 (xxx.xxx.xxx.es): 14 times

In our case, we also modified $TMP_PATH/services/pam_unix, $TMP_PATH/services/secure/filters and added some strings to be ignored in /etc/logwatch/conf/ignore.conf.

Comandos Avanzados, General, Linux, Scripting

Variables de entorno y comando export

January 13th, 2014

Regla mnemotécnica

export: Exportar (en ingles) al entorno

Variables de entorno

Las llamadas variables de entorno se definen a nivel de sistema operativo para el correcto o mejor funcionamiento del mismo. Muchas de ellas son predefinidas pero cada usuario puede definir también sus propias variables para su entorno. El funcionamiento de las variables de entorno es el mismo que las variables normales. Se suelen diferenciar usando normalmente letras mayúsculas para definirlas.

El comando export

El comando export es el que nos permite crear o modificar variables de entorno. Así

export VARIABLE-NAME

nos exporta VARIABLE-NAME o

export VARIABLE-NAME=valor

nos define y exporta VARIABLE-NAME como variable en entorno al mismo tiempo que el asigna un valor. Si no usásemos el comando export, VARIABLE-NAME se mantendría como una variable normal.

Ejemplos

USER Contine el nombre del usuario.
HOSTNAME Contine el nombre de la máquina.
HOME Indica cual es el directorio home del usuario.
PATH Contine los lugareres o paths del sistema donde se buscarán programas y comandos.
SHELL Indica cual es el intérprete de comando que se esta usando.

Es importante por ejemplo la variable PATH que nos dice donde se encuentran comandos tipo ls, cp, if, etc para su ejecución. Podemos mostrar su valor con

$ echo $PATH

Como veis cada path diferente viene separado por “:“. Podemos modificarla para que busque comandos y programas en la carpeta bin de nuestro home, donde podremos poner nuestros propios programas y scripts para poder ejecutarlos fácilmente desde cualquier directorio sin necesidad de copiarlos.

$ PATH=$PATH:$HOME/bin
$ export PATH
$ #Que es equivalente a ejecutar directamente
$ export PATH=$PATH:$HOME/bin
$ echo $PATH

Como veis hemos añadido al final a la variable PATH la carpeta $HOME/bin, y hemos usado la variable de entorno $HOME. Hay que tener cuidado de añadir y no sustituir con:

$ export PATH=$HOME/bin
$ echo $PATH

donde el comando echo no funcionará pues nuestro PATH será únicamente $HOME/bin, no puede ejecutar el comando echo ni ningún otro porque no va a buscar comandos a ningún otro sitio. Lo más sano en este caso es cerrar la terminal y abrir otra.

Comandos Avanzados, Linux

Comando while de Linux

November 18th, 2013

Regla mnemotécnica

while: Mientras en ingles.

While

El comando while es una instrucción de control de flujo que permite ejecutar una serie de comandos repetidamente sobre la base de una condición dada, es decir, genera un bucle. Cuando la condición deje de cumplirse, la ejecución del programa saldrá del bucle y no realizará más iteraciones. En los bucles while siempre hay que asegurarse de que siempre exista la condición que nos sacará del mismo, sino, entraremos en los peligrosos bucles infinitos donde se ejecuta la secuencia infinitamente. En caso de suceder esto es útil saber que podemos pulsar CTRL+C que mata el comando en curso.

Estructura del comando while

El comando while tiene la siguiente estructura

while [ condicion ]
do
    comandoA
    comandoB
done

donde los comandos entre do y done se ejecutan mientras se cumple la condición y se pueden poner tantos comandos como se desee. Si deseamos escribirlo en una línea este queda como:

while [ condicion ]; do comandoA ; comandoB ; done

Algunas expresiones que podemos usar como condición ya las ilustramos con el comando condicional if y puedes consultarlas en ese enlace. Se puede usar el comando continue para saltar a la siguiente iteración del bucle y el comando break para interrumpirlo. Veámoslo mejor con unos ejemplos.

 

Ejemplos Básicos

Aquí tenemos un bucle básico con while

i=1
while [ $i -le 10 ]
do
    echo "Estamos en la iteración $i"
    ((i++))
done

donde se imprimirá en pantalla "Estamos en la iteración 1", 2, 3, etc. hasta 10. Cuando ya no se cumple que i es menor o igual (-le: less or equal) a 10 se sale del bucle. ((i++)) es equivalente a i=$(($i+1)) e incrementa el contador i en una unidad. Ahora vamos a  ejecutar el mismo bucle pero saltándonos la iteración 4.

i=0
while [ $i -le 10 ]
do
    ((i++))

    if [ $i == 4 ]
    then
        continue
    fi
    echo "Estamos en la iteración $i"
done

Vemos que cuando i==4 vuelve de nuevo al inicio del bucle y no ejecuta la orden echo. Es importante como hemos cambiado el incremento del índice i al principio del bucle. Si estuviese al final el bucle se quedaría ejecutándose infinitamente con el valor i=4. Si en vez del comando continue hubiésemos usado el comando break, en la iteración 4 habría terminado la ejecución del comando while, se rompe el blucle, y continuaría con el script. También podemos crear un bucle infinito y usar el comando break para salir de él. En el siguiente ejemplo si el fichero abort no existe el bucle se ejecuta infinitamente, en el momento en que se crea el fichero abort, se detecta mediante el if, se sale del bucle.

while [ 1 == 1 ]
do
    echo "Estoy en el bucle."

    if [ -f abort ]
    then
        echo "El fichero abortar exite. Saliendo..."
        break
    fi
done

Por supuesto, también se pueden ejecutar bucles anidados, unos dentro de otros, como en el siguiente ejemplo.

i=1
while [ $i -le 5 ]
do
    #Para cada i un buble descendente hasta el valor i
    j=5
    while [ $j -ge $i ]
    do 
        echo "Estamos en la iteración i=$i j=$j"
        ((j--))
    done
    ((i++))
done

 

Ejemplos en un entorno de cálculo

Ejemplo 1:  Ejecutar el comando qstat -u $USER cada 30 minutos, donde $USER es una variable de entorno que define al usuario. La ejecución del bucle no modifica la condición de salida por lo que estamos ante un bucle infinito.

a=1
while [ $a == 1 ]
do
    qstat -u $USER
    #Esperamos sin hacer nada 1800 segundos, 20 minutos
    sleep 1800
done

Ejemplo 2: Mandar 10 trabajos (1.pbs, 2.pbs, …,10.pbs) a un sistema de colas PBS/Torque con el comando qsub:

x=10
while [ $x != 0 ]
do
    qsub $x.pbs
    x=$(echo $x-1 | bc)
done

o en una sola línea:

x=10; while [ $x != 0 ]; do qsub $x.pbs; x=$(echo $x-1 | bc); done

 

 

Comandos Avanzados, Linux

Comando case en Linux

October 28th, 2013

Regla mnemotécnica

case: En caso de en ingles in case.

Estructura del Comando Case

El comando case es una forma de ejecución condicional que nos permite ejecutar unos u otros comandos según el valor de una variable. No incluye ninguna funcionalidad nueva que no pueda ser realizada con el uso del comando if, pero en ciertos casos la sintaxis es más sencilla, intuitiva y directa. Con el comando case se lee una variable, si su valor coincide con alguno esperado se ejecutan los comandos asociados a ese valor. La sintaxis es como indicamos a continuación:

case $variable in

valor-1) 
    comandos
;;
valor-2) 
    comandos
;;
...
*)       
    comandos
esac

donde $varible es la variable que leemos, si tiene el valor-1 ejecuta los comandos que se encuentran a continuación hasta que se encuentran ";;" que indica el fin de los comandos asociados a ese valor de la variable. Se pueden definir cuantos posibilidades sean necesarias y como última opción podemos añadir el comodín "*)" y si la ejecución llega hasta este punto ejecutará los comandos para este caso. Si no existe "*)" y la variable no toma ninguno de los valores predefinidos evidentemente no se ejecuta nada. Veamos un ejemplo:

nombre=gabriel

case $nombre in
txomin)    echo "No soy Gabriel"
           echo "Soy Txomin"
;;
gabriel)   echo "Soy Gabriel"
;;
*)         echo "No soy Txomin"
           echo "Ni tampoco soy Gabriel"
esac

Evidentemente la ejecución de este script dará como salida "Soy Gabriel" y es fácil ver que será lo que hará dependiendo del valor que le asignemos a la variable $nombre. También podemos usar el comando booleano “or”  (o) con el símbolo “|” para indicar varios posibles valores asociados a los mismos comandos.

nombre=gabriel

case $nombre in
txomin|gabriel)
           echo "Soy Gabriel o Txomin"
;;
*)         echo "No soy Txomin"
           echo "Ni tampoco soy Gabriel"
esac

Comandos Avanzados, Linux

Comando if en Linux

October 24th, 2013

Regla mnemotécnica

if: Conjunción si en ingles.

Estructura del condicional

El condicional if es un comando que nos permite ejecutar una secuencia de comandos dependiendo de la condición especificada. Con la misma podemos controlar la ejecución de un código en base a las necesidades establecidas por los condicionantes.

El modo mas simple de una sentencia condicional es:

if [ condición ]
then
    comandos 
fi

o en una única línea

if [ condición ] ; then comandos ; fi

En los siguientes ejemplos usaremos la primera sintaxis por ser más clara. En el ejemplo previo, si la condición se cumple se ejecutarán los comandos que introduzcamos hasta el cierre del condicional con fi.  Hay que tener en cuenta que la condición ha de ir entre corchetes [ ] respetando los espacios en blanco entre los corchetes y la condición. Una versión algo más compleja puede incluir más posibles condiciones:

if [ condición-1 ]
then
    comandos1
elif [ condición-2 ]
then
    comandos-2
fi

donde elfi es una contracción de else if. Primero se evalua la condición-1 y si se cumple se ejecutan los comandos-1 y se sale del condicional, no se evalúan los siguientes. Si no se cumple la condición-1 se evalúa la condición-2 y si se cumple se ejecutan los comandos-2 y si no se sale del condicional. Se pueden escribir tantos elif como se desee. La última versión y más compleja estructura de condicional incluye la condición final else:

if [ condición-1 ]
then
    comandos-1
elif [ condición-2 ]
then
    comandos-2
else
    comandos-3
fi

Aquí si no se cumple la condición-1 ni la condición-2 se entra en el else y se ejecutan los comandos-3. Veamos un ejemplo.

a=hola
if [ $a == 1  ]
then
    echo "a es igual a 1"
elif [ $a == "adios" ]
then
    echo "a es igual a adios"
else
    echo "a nos es ni 1 ni adios"
fi

En este caso evidentemente veremos en pantalla el último mensaje “a no es ni 1 ni adios”.  Observemos  como la condición de igual se construye con dos signos [ a == 1] dado que con [ a = 1 ] lo que estamos haciendo es asignar a la variable a el valor 1. Algunos de los condicionantes más comunes son:

 == Igual que, tanto para números enteros como palabras
!= Diferente que, tanto para números enteros como palabras
-eq Igual que (equal), sólo para números enteros
-ne Diferente que (non equal), sólo para números enteros
-gt Mayor que (greater than)
-ge Mayor o igual que (greater or equal than)
-lt Menor que (less than)
-le Menor o igual que (less or equal than)
! Negación, invierte el condicional
-f nombre El fichero regular nombre existe
-d nombre El directorio nombre existe

Ejemplos

Tres breves ejemplos. En el primero verificamos si el fichero regular datos.txt existe y en ese caso lo mostramos:

if [ -f datos.txt ]
then
    echo "datos.txt existe"
    cat datos.txt
fi

En el segundo ejemplo verificamos si el fichero regular datos.txt no existe y en ese caso lo creamos vacío:

if [ ! -f datos.txt ]
then
    echo "datos.txt existe"
    touch datos.txt
fi

En el tercer ejemplo usamos la salida de un comando dentro del condicional. Para ellos listaremos en un columna los ficheros y directorios del directorio actual terminados en txt con el comando ls, le pasaremos el resultado con una tubería (|) al comando wc y contaremos con este el número de ficheros Para tratar la salida de un comando como variable este ha de ir dentro de $( ).

#Primero simplemente mostramos el resultado para verificar
ls *txt |wc 
#Ahora ejecutamos el ejemplo de condicional
if [ $(ls *txt |wc) -gt 0 ]
then
    echo "Existen ficheros txt. Los borramos"
    rm *txt
fi

En este script hemos borrado los ficheros *txt y hemos evitado que el script de error en caso de no existir ninguno.

Condicionales complejas

Se pueden construir condicionales complegas donde se conjugan varias de ellas a través de los operadores los booleanos “y” &&, “o” (||) y negación (!), este último que ya hemos visto. Ilustrémolos con un par de ejemplos en los que usaremos comando date para obtener información sobre el día de hoy. Con “o” basta que se cumpla una de las dos condiciones :

#Asignamos a la variable today el día de la semana.
today=$(date +%A)
#Evaluamos el condicional.
if [ $today == "lunes" ] || [ $today == "martes" ]; then
    echo "Hoy es lunes o martes."
fi

Con “y” han de cumplirse ambas condiciones:

#Asignamos a la variable today el día de la semana.
dia=$(date +%e)
mes=$(date +%B)
#Evaluamos el condicional.
if [ $mes == "marzo" ] && [ $dia == "13" ]; then
    echo "Hoy es mi cumpleaños."
fi

El operador && siempre se evalua antes que ||, pero se puede alterar esto agrupando los comando con paréntesis. Por ejemplo:

( [  cond-1 ] || [ cond-2 ] ) && ( [  cond-3 ] || [ cond-4 ] )

 

 

 

Comandos Avanzados, Linux

Variables y arrays en Linux

October 14th, 2013

En Linux se pueden definir variables y arrays para facilitar la programación. La diferencia es que una variable almacena un dato mientras que un array almacena varios y se puede acceder a ellos individualmente.

Variables

Para asignar una variable usamos simplemente el nombre que queremos usar pero para mostrar su valor usamos el comando echo y la variable precedida del símbolo "$", para indicar que queremos que echo nos devuelva el valor de la variable y no el nombre que indicamos. Veamos unos ejemplos:

 $ a=1

 $ #Imprimimos la cadena literal a
 $ echo a
 a

 $ #Imprimimos la varible a
 $ echo $a
 1

 $ #Otros ejemplos
 $ variable1=cascanueces
 $ echo $variable1
 cascanueces
 $ kpj33='Entrecomillado para usar espacios'
 $ echo $kpj33
 Entrecomillado para usar espacios

 $#Asignamos a una varible otra variable
 $ a=xy
 $ b=$a
 $ echo $b
 xy

 $ #Con comillas simples no interpreta la variable
 $ #en el siguiente ejemplo $a
 $ c='La variable a tiene por valor $a'
 La variable a tiene por valor $a

 $ #En general en linux las comillas dobles
 $ #si interpretan las variables
 $ c="La variable a tiene por valor $a"
 La variable a tiene por valor xy

Arrays

Los arrays tienen una sintaxis diferente para asignarlos a las variables, precisamene para poder diferenciarlos. Posteriormente se pueden mostrar los elementos uno a uno.El índice del primer elemento es el 0 no el 1. Veámoslo con unos ejemplos.

 $ #v es una variable
 $ v="a b c"
 $ #a es un array
 $ a=(a b c)

 $ #Puedo imprimir la variable v
 $ echo $v
 a b c

 $ #La misma sintaxis me imprimirá solo el primer elemento de un array
 $ echo $a
 a

 $ #Que equivale a
 $ echo ${a[0]}
 a

 $ #Para imprimir cualquier elemento
 $ echo ${a[1]}
 b
 $ echo ${a[2]}
 c

 $ #Para imprimir todos
 $ echo ${a[*]}
 a b c

 $ #Curiosamente se admiten expresiones matemáticas, para imprimir el elemento 2=1+1
 $ echo ${a[1+1]}
 c

La sintaxis de array solo funciona para variables, o si se aplica a una variable la interpreta como un array de un elemento

 $ v="a b c"
 $ echo ${v[0]}
 a b c
 $ echo ${v[1]}

 $ #El elemento 1 ya no existe

Nos ha imprimido el resultado correcto en el primer caso, pero dado que no existe un segundo elemento en el segundo ejemplo no imprime nada. Por último, podemos obtener el número de elementos de un array “contándolos” con el símbolo "#":

 $ v=(a b c d)
 $ echo ${#v[*]}
 4

Asignando la salida de un comando

Podemos utilizar la salida de un comando a modo de variable generalmene en cualquier contexto y en particular para asignarlo a una variable ejecutándolo entre $(). Para ellos usaremos el comando seq. Veamos un ejemplo de creación de una variable:

 $ seq 1 5
 1 2 3 4 5
 $ v=$(seq 1 5)
 $ echo $v
 1 2 3 4 5

De forma similar para crear un array con la sintaxis de un array usando ():

 $ v=($(seq 1 5))
 $ echo ${#v[*]}
 5
 $ echo ${v[2]}
 3

Comandos Avanzados, Linux

Comando date en Linux

October 1st, 2013

Regla mnemotécnica

date: Fecha en ingles.

El comando date nos permite imprimir la fecha de hoy en muchísimos formatos. También nos permite extraer solo el día, mes, día de la semana, etc. Es útil en la ejecución de scripts pues nos permite saber cuando se ha ejecutado, por ejemplo si estos se ejecutan de forma automática en ciertas cirscustancias. Si lo ejecutamos sin argumentos nos imprime la fecha de hoy en formato largo.

$ date
mié sep 25 12:31:17 CEST 2013

Si queremos controlar el formato tenemos que usar una sintaxis tipo

$ date +formato

donde en formato tenemos muchas posibilidades. Algunas de ellas las indicamos en la siguiente tabla. No obstante, lo mejor para conocer todos los posibles formatos es usar el comando de ayuda man con man date que nos mostrará el manual de date.

%a Día de la semana abreviado (lun, mar, etc)
%A Día de la semana (lunes, martes, etc)
%b Més abreviado (ene, feb, mar, abr, etc
%e Día del mes (1,2,..,31)
%D Fecha en formato dd/mm/aa
%H Hora en formato 00,..,23
%M Minutos en formato 00,..,59
%T Hora completa en formato hh:mm:ss (24 horas)
%W Semana del año, el lunes el primer día (00,..,53)

Así por ejemplo:

#Manual de date
$ man date

#Diferentes comandos de date
$ date +%a
lun

$ date +%T
22:15:35

$ date +%H%M
2215

También se puede intercalar texto como en los siguientes ejemplos:

#Sin texto
$ date +%H%M
2215

#Con texto, no podemos incluir espacios en blanco
$ date +hora%Hdia%M
hora22dia15

#Pero podemos formatearlo mejor entrecomillando el texto
$date +"hora: "%H" - dia: "%M
hora: 22 - dia: 15

Se puede usar el comando date para indicarle una fecha específica con la opción -d como en los ejemplos:

#La fecha de ayer 
$ date -d yesterday
mar sep 24 12:31:17 CEST 2013

#La fecha de mi cumpleaños
$ date -d 02/17/76
mar feb 17 00:00:00 CEST 1976

$ date -d 02/17/76 +"Nací un "%A
Nací un martes

 

 

 

Comandos Avanzados, Linux

bc, let y expresiones matemáticas en Linux

July 23rd, 2013

Regla mnemotécnica

bcBasic Calculator

El comando bc es una calculadora que se puede usar dese la línea de comandos. Esta herramienta ofrece muchas posibilidades. En nuestro caso la presentaremos para realizar operaciones muy básicas, y más adelante veremos su utilidad en los scripts.

Si ejecutamos bc y entramos en su consola y podemos realizar operaciones y nos irá imprimiendo el resultado. Veamos un ejemplo:

$ bc
7+5
12
((7+5)/2)^2
36
1.1*3
3.3
quit

 

Su utilidad dentro de los scritps reside en la posibilidad de realizar operaciones utilizando las tuberías para pasarle operaciones matemáticas y que nos devuelva el resultado. veamos unos ejemplos:

$ echo 7+5*2 | bc
17
$echo (3^5-sqrt(16))/2 | bc
119

 

Podemos actualizar el valor de variables. Guardamos en actualizamos el valor de una variable con una operación matemática y=y+1 en la variable y:

$ y=1
$ y=$(echo $y+1 | bc)
$ echo $y
2

 

Expresiones mátemáticas en bash

Para trabajar con operaciones simples (+,-,* y /) y números enteros y asignarlo a variables es el comando let o la sintaxis $(( )). Veamos como reescribiríamos el ejemplo anterior con let:

$ y=1
$ let y=y+1
$ echo $y
2

y con la sintaxis para operaciones matemáticas

$ y=1
$ y=$((y+1))
$ echo $y
2

 

Estos dos comandos cuando trabajamos con números reales truncan el resultado y dan error si tratamos de escribir un número decimal. Así obtenemos el resultado el resultado incorrecto con:

$ y=$((7/4))
$ echo $y
1

en vez de 1.75 que es el correcto.

.

Comandos Avanzados, Linux

Tuberías y redirecciones en Linux

July 5th, 2013

Las redirecciónes nos permiten en Linux redirigir la entrada o salida estándar desde o hacia un fichero, respectivamente. La tubería nos permite usar la salida de un comando como entrada para otro, permitiendo concatenar comandos.

 

Redirecciones

Primero señalar que en cuando hablamos de la entrada estándar se hace referencia, normalmente, a lo escrito a través del teclado y como salida estándar a lo envíado a la pantalla, aunque pueden ser otros los dispositivos definidos como estándar en algún caso especial. Las redirecciones se realizan con los símbolos > y < usando su similitud con unas flechas. Así con el símbolo > podemos redirigir la salida estándar desde un comando hacia un fichero. La redirección es muy útil cuando la salida es muy larga y no nos cabe en pantalla, cuando necesitamos o nos es conveniente guardarla en un fichero, etc. Veamos un ejemplo.

$ echo "Hola mundo"
Hola mundo
$ echo "Hola mundo" > saludo
$ cat saludo
Hola mundo

Como vemos en el ejemplo con el comando echo mandamos a pantalla un mensaje, pero si usamos la redirección > mandamos el mensaje al fichero saludo. Luego con el comando cat hemos mostrado el contenido del fichero que hemos creado. Para añadir información a un fichero existente, sin sobreescribirlo se usa >>. Veamos otro ejemplo:

$ echo "Hola mundo"
Hola mundo
$ echo "Hola mundo" > saludo
$ cat saludo
Hola mundo
$ echo "Ahora he sobreescrito el fichero saludo" > saludo
$ cat saludo
Ahora he sobreescrito el fichero saludo
$ echo "Pero ahora le he añadido otra línea" > saludo
$ cat saludo
Ahora he sobreescrito el fichero saludo
Pero ahora le he añadido otra línea

Como vemos en este ejemplo > destruye el contenido del fichero si existe pero >> añade la información al final.

El símbolo < permite enviar el contenido de un fichero como entrada estándar. Esto es útil, por ejemplo, en programas o comandos en los que introducimos o podemos introducir los argumentos por el teclado, de tal manera que podemos sustituirlos por un fichero. Un ejemplo tirivial con cat es:

$ echo "Hola mundo" > saludo
$ cat < saludo
Hola mundo

 

Tuberías

Las tubería es una redirección especial que nos permite enviar la salida de un comando como entrada de otro, para ellos se usa el símbolo |. Su gran útilidad es que nos permite concatenar comandos enriqueciendo mucho la programación. Veamos unos sencillos ejemplos con seq y head:

$ seq 1 5 |head -2
1
2

 

Redirecciones, avanzado

También exite la salida de error que va por otro ‘canal’ diferente. Así por ejemplo si el fichero file1 existe y el file2 no tenemos el siguiente comportamiento

$ ls file1 file2
ls: no se puede acceder a file2: No existe el archivo o el directorio
file1
$ ls file1 file2 > salida
ls: no se puede acceder a file2: No existe el archivo o el directorio
$ cat salida
file1

Como vemos, cuando hemos redirigido la salida al fichero salida, el mensaje de error que nos informa que el fichero file2 no existe sigue saliendo por pantalla. Para poder redireccinar también la salida de error tenemos que usar &> que nos dice que redireccionemos ambas salidas, así:

$ ls file1 file2 &> salida
$ cat salida
ls: no se puede acceder a file2: No existe el archivo o el directorio
file1

De hecho la salida estándar suele ir identificada con 1 (o &1 si va despues de > para diferenciarla de un fichero con nombre 1), y la salida de error con 2 (o &2) para poder hacer redirecciones individuales. Así, es equivalente a redirigir la sólo salida el siguiente comando:

$ ls file1 file2 1> salida
ls: no se puede acceder a file2: No existe el archivo o el directorio
$ cat salida
file1

Para redirigir la salida de error a un fichero

$ ls file1 file2 2> salida
file1
$ cat salida
ls: no se puede acceder a file2: No existe el archivo o el directorio

2>&1 o 1>&2  sirven para redirigir la salida de error a la estandar  o viceversa para luego, por ejemplo, enviarla con una tubería a otro comando.

$ ls file1 file2 2>&1 salida |wc -l
2

 

 

Comandos Avanzados, Linux

Scripts en Linux

June 24th, 2013

Un script en linux es un programa escrito en el lenguaje de Linux, es decir, una concatenación de comandos. Los scripts son muy útiles para realizar acciones que repetimos habitualmente y que suponen la ejecución de varios comandos o para ejecutar una concatenación compleja de acciones, que es más fácil de ir escribiendo y corriguiendo si lo hacemos como si se tratase de un programa. De este modo escribimos todos los comandos que queremos ejecutar en un fichero de texto con un comando por línea. Así ya hemos creado un script que cuando lo ejecutemos será equivalente a ejecutar todos los comandos que tenemos en el script.

Tux

Tux

La potencia de los scripts en Linux tal vez no se aprecie con el programa que ponemos como ejemplo, pero conforme vaya aumentando nuestro conocimiento de Linux, con más comandos y más complejos podremos automatizar tareas muy complejas. Con este post, de hecho creamos, la sección de “comandos avanzados”, donde describiremos comandos de interés para la programación de tareas complejas.

Veamos un ejemplo sencillo. Escribiremos un fichero de texto plano (no un .odt, .xdoc o similar que aparte del texto visible contiene mucha información “oculta” para darle el formato) que contenga las siguientes líneas y que llamaremos hola.sh:

#!/bin/bash

mkdir TMP
cd TMP
touch newfile.txt
echo "Hola mundo, el fichero ha sido creado"
ls

 

En este simple script hemos creado el directorio TMP con mkdir, nos hemos metido dentro de este directorio con cd, hemos creado un fichero vacío llamado newfile.txt con el comando touch, mostramos en pantalla un mensaje empleando el comando echo y listamos los ficheros que existen en el directorio con el comando ls. La primera línea es un poco especial e indica que “lenguaje queremos utilizar” (que shell). En este caso usamos bash que es el más común.

No obstante, no vamos a poder ejecutar el fichero hola.sh pues es un fichero de texto sin permiso de ejecución. Para darle permiso de ejecución usamos el comando chmod.

Tras darle permiso para ejecutarse a nuestro script hola.sh, dependiendo de la configuración de nuestro Linux, para ejecutar nuestros scripts debemos indicarle el donde está, en este caso si está en nuestra carpeta se indica explícitamente precediendo el nombre con “./". Si lo ejecutamos obtenemos:

$ chmod u+x hola.sh
$ ./hola.sh
Hola mundo, el fichero ha sido creado
hola.sh   newfile.txt

 

Donde nos muestra en una línea el mensaje del que hemos enviado a pantalla con echo y en la siguiente el resultado del comando ls.

La potencia de los scripts en Linux tal vez no se aprecie con un programa tan sencillo, pero conforme vaya aumentando nuestro conocimiento de Linux, con más comandos y más complejos podremos automatizar tareas muy complejas.

 

Comandos Avanzados, Linux