_
). Pero no pueden comenzar por un número y
es tradición usar letras mayúsculas para diferenciarlas bien de las
órdenes. Son nombres de variables válidos, pues,
Pepa
, Avelino
, BURLA2
, _MmMmM_
,
etc. Y no lo serán, 6TOROS6
, HOL@
y así.
<gyermo@ENCINA>/usuarios/profes/gyermo$ CENTRO='Facultad de Ciencias'El apóstrofo, que es el carácter que se encuentra en el teclado español debajo del signo de cierre de interrogación, no es obligatorio, pero observad qué es lo que ocurre si no lo ponemos:
<gyermo@ENCINA>/usuarios/profes/gyermo$ UNIVERSIDAD=Universidad de Salamanca bash: de: command not foundAl encontrarse un espacio en blanco, el ordenador se cree que ahí acaba la cadena. Asigna
Universidad
a la variable
UNIVERSIDAD
y trata de ejecutar la palabra de
como
si de una orden se tratase. Como no lo es, nos da el mensaje en inglés
de orden no encontrada.
$
):
<gyermo@ENCINA>/usuarios/profes/gyermo$ $CENTRO bash: Facultad: command not foundDe nuevo, obtenemos un error pero es evidente el porqué. Antes de ejecutar cualquier orden el ordenador sustituye las apariciones de las variables por su correspondiente valor. A continuación, se dispone a ejecutar el resultado y se piensa que la primera palabra (
Facultad
) es una orden que
le estamos dando y no la entiende. Si lo que queremos es que nos muestre el
contenido de una variable, necesitamos una orden nueva para ello. La orden es
echo
:
<gyermo@ENCINA>/usuarios/profes/gyermo$ echo $CENTRO Facultad de Ciencias <gyermo@ENCINA>/usuarios/profes/gyermo$ echo Mi centro es la $CENTRO Mi centro es la Facultad de CienciasEjercitémonos con las variables. Vamos a mostrar el resultado del último partido de fútbol del Trofeo Rector, con ayuda de la variable
CENTRO
y otra nueva, CENTRO2
, de
modo que aparezca exactamente esto por la pantalla:
Facultad de Ciencias2‑Derecho0
(*):
<gyermo@ENCINA>/usuarios/profes/gyermo$ CENTRO2=Derecho <gyermo@ENCINA>/usuarios/profes/gyermo$ echo $CENTRO2-$CENTRO20 Derecho-¿Qué es lo que ha ocurrido? ¿Por qué no nos obedece el ordenador? La respuesta es simple. Porque no adivina nuestros pensamientos. Al poner
$CENTRO2
él se piensa que
pedimos que imprima la variable CENTRO2
e imprime esa variable,
que vale Derecho
. En estos casos ambiguos, tenemos que
ayudarle para que sepa hasta dónde llega el nombre de la variable.
Lo hacemos con ayuda de las llaves:
<gyermo@ENCINA>/usuarios/profes/gyermo$ echo ${CENTRO}2-${CENTRO2}0 Facultad de Ciencias2-Derecho0Otra sutileza que debéis saber: al ser el espacio en blanco un separador, para el ordenador lo mismo le da 1 que 80. Tratemos de que salga por la pantalla:
Facultad␣de␣Ciencias,␣␣␣Universidad␣de␣Salamanca
.
En la cadena se han marcado con ␣
los espacios para
que veáis que hay tres entre la coma y Universidad
:
<gyermo@ENCINA>/usuarios/profes/gyermo$ echo $CENTRO, $UNIVERSIDAD Facultad de Ciencias, Universidad de SalamancaAunque hemos puesto tres espacios, como el espacio actúa de separador, el ordenador lo trata como si fuera uno. ¿Y si ponemos la frase entre apóstrofos? Recordad que podéis usar las flechas para editar la orden anterior y ahorrar tiempo...
<gyermo@ENCINA>/usuarios/profes/gyermo$ echo '$CENTRO, $UNIVERSIDAD' $CENTRO, $UNIVERSIDAD¡Uy! Parece que hemos logrado que salgan los tres espacios en blanco después de la coma, pero el ordenador toma todo al pie de la letra. Incluso el signo
$
lo interpreta tal cual y no
como indicador de que lo que viene a continuación es una variable.
Si solamente tuviéramos la posibilidad de que hubiera algo que
le dijera al ordenador que interpretarse todo literalmente salvo
el carácter $
... Pues lo hay:
<gyermo@ENCINA>/usuarios/profes/gyermo$ echo "$CENTRO, $UNIVERSIDAD" Facultad de Ciencias, Universidad de SalamancaNos basta con ponerlo entre comillas dobles. Las comillas dobles, aparte del significado de
$
, también respetan los significados
de !
, \
y `
. Alguno de
ellos los veremos después. El último es el acento francés
parecido al nuestro, pero mirando a Cuenca. En el teclado español
se obtiene pulsando la tecla de dicho acento y la barra espaciadora a
continuación. ¿Con el siguiente ejemplo adivináis para
qué sirve?
<gyermo@ENCINA>/usuarios/profes/gyermo$ LISTADO=`ls` <gyermo@ENCINA>/usuarios/profes/gyermo$ echo $LISTADO backup bin CARTAS chgrp.2 gyermo-encina-2005-03.tar.gz mail MANTEJO PRIVADO PRUEBA public_html SESION3 SESION6 TEMPPor si andáis un poco despistadillos, esta es la respuesta: lo que pongáis dentro de un par de esos acentos, primero lo ejecuta el ordenador y el resultado, en lugar de sacarlo por la pantalla, lo pone en lugar del par de acentos y su contenido, como si estuviera entre apóstrofos. Dicho de otro modo, primero ejecuta el
ls
que le hemos puesto en el ejemplo y, después, es como si alguien
hubiera tecleado la siguiente línea:
<gyermo@ENCINA>/usuarios/profes/gyermo$ LISTADO='backup bin CARTAS chgrp.2 gyermo-encina-2005-03.tar.gz mail MANTEJO PRIVADO PRUEBA public_html SESION3 SESION6 TEMP'¿Sabríais responder qué es lo que pasará si tecleáis
echo `ls`
? Hacedlo. ¿Lo
habéis adivinado?
unset
:
<gyermo@ENCINA>/usuarios/profes/gyermo$ UNIVERSIDAD="Universidad de Salamanca" <gyermo@ENCINA>/usuarios/profes/gyermo$ echo Mi universidad es la $UNIVERSIDAD Mi universidad es la Universidad de Salamanca <gyermo@ENCINA>/usuarios/profes/gyermo$ unset UNIVERSIDAD <gyermo@ENCINA>/usuarios/profes/gyermo$ echo Mi universidad es la $UNIVERSIDAD Mi universidad es la____________________________
\
es muy parecido al que tiene
en C. Seguido de ciertas letras permite referirse a caracteres de control.
Como al tener ese uso, el propio carácter queda invalidado para
representarse a sí mismo, si lo que queremos es que aparezca uno
de estos caracteres en la cadena, debemos doblarlo (\\
).
El carácter \
en el contexto que nos ocupa también
sirve para privar de su significado especial a otros caracteres como
$
o el espacio en blanco, sin necesidad de que los metamos
entre apóstrofos. Así, por ejemplo, para que podamos imprimir
esta cadena o asignarla a una variable sin usar apóstrofos:
La␣cuenta␣asciende␣a:␣␣␣\$137,03\
,
debemos escribir:
<gyermo@ENCINA>/usuarios/profes/gyermo$ echo La\ cuenta\ asciende\ a:\ \ \ \\\$137,03\\ La cuenta asciende a: \$137,03\Si lo asignamos a una variable, debemos tener cuidado, pues aunque dentro de la variable estén los tres espacios, el ordenador los vuelve a colapsar en uno si no tenemos cuidado:
<gyermo@ENCINA>/usuarios/profes/gyermo$ CUENTA=La\ cuenta\ asciende\ a:\ \ \ \\\$137,03\\ <gyermo@ENCINA>/usuarios/profes/gyermo$ echo $CUENTA La cuenta asciende a: \$137,03\ <gyermo@ENCINA>/usuarios/profes/gyermo$ echo "$CUENTA" La cuenta asciende a: \$137,03\El significado especial del carácter
!
no lo veremos en
estas prácticas. El que esté interesado puede consultar la
página de manual de la orden bash
.
<gyermo@ENCINA>/usuarios/profes/gyermo$ n[4]=no n[6]=no n[8]=no n[9]=no n[10]=no n[12]=no n[14]=no <gyermo@ENCINA>/usuarios/profes/gyermo$ echo 7 ${n[7]} es un número primo 7 es un número primo <gyermo@ENCINA>/usuarios/profes/gyermo$ echo 12 ${n[12]} es un número primo 12 no es un número primoPara referirse a un elemento del array, como veis, es necesario usar las llaves.
<gyermo@ENCINA>/usuarios/profes/gyermo$ m[0]=3 m[1]=1 m[3]=1 <gyermo@ENCINA>/usuarios/profes/gyermo$ echo ${m[*]} 3 1 1 <gyermo@ENCINA>/usuarios/profes/gyermo$ echo ${!m[*]} 0 1 3Notad que el elemento de índice 2 está ausente. En las versiones modernas de la shell, también se dispone de arrays asociativos (esto es, aquellos cuyos índices pueden ser cadenas de caracteres). En este ejemplo, usamos uno para guardar la edad de una serie de personas:
gyermo@mirto:~$ declare -A EDAD gyermo@mirto:~$ EDAD[Lucas]=40 EDAD[Silvia]=37 EDAD[JonAs]=3 EDAD[Daniel]=1 gyermo@mirto:~$ echo La edad de JonAs es ${EDAD[JonAs]}. La edad de JonAs es 3.También funciona, en este caso, tanto el listado de valores como el de índices, aunque no se respeta el orden de asignación:
gyermo@mirto:~$ echo ${EDAD[*]} 3 40 1 37 gyermo@mirto:~$ echo ${!EDAD[*]} JonAs Lucas Daniel SilviaAl igual que ocurre con las variables, se puede borrar un array completo o alguno de sus elementos mediante la orden
unset
.
eval
. Toma una expresión cualquiera, la
expande y el resultado de la expansión lo ejecuta. Esto
incluye, cómo no, expresiones contenidas en variables.
Por ejemplo:
<gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ ORDEN="ls -l" <gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ eval $ORDEN total 4 lrwxrwxrwx 1 gyermo profes 14 ago 19 19:40 ReyesMagos.txt -> SantaClaus.txt -rw-r--r-- 1 gyermo profes 186 ago 19 18:57 SantaClaus.txt
PS1
, por ejemplo.
HOSTNAME
: almacena el nombre del ordenadorHOSTTYPE
: tipo de servidor (tipo de procesador)OLDPWD
: último directorio en que hemos estadoOSTYPE
: tipo de sistema operativoPWD
: ruta del directorio de trabajoRANDOM
: cada vez que se lee, devuelve un número al azar
de 0 a 32767REPLY
: se almacena lo tecleado por el usuario después de
invocar la orden read
SECONDS
: nos dice cuántos segundos llevamos conectadosHOME
: ruta del directorio de conexiónLANG y LC_...
: usadas para establecer el locale, como se ha vistoPATH
: lista de directorios donde se buscan las órdenes y
programas que teclea el usuarioPSx
: permite establecer los distintos indicadores
(prompts)PATH
.
La mayor parte de órdenes de UNIX no son sino programas que han hecho otras
personas, los han compilado y se encuentran en algún directorio del disco
duro. Cuando tecleamos una orden, como ls
, el ordenador busca un
programa que se llame así y lo ejecuta. ¿Dónde lo busca?
Pues en los directorios que se especifiquen en la variable de entorno PATH
.
Si queremos saber dónde encuentra a un determinado programa, podemos usar
la orden which
:
<gyermo@ENCINA>/usuarios/profes/gyermo$ echo $PATH /opt/SUNWspro/bin:[...]:/usr/bin:/usr/local/bin:[...]:/home/gyermo/bin:/usr/bin:/usr/ucb:/usr/ccs/bin:/etc:. <gyermo@ENCINA>/usuarios/profes/gyermo$ which ls /usr/bin/ls <gyermo@ENCINA>/usuarios/profes/gyermo$ ls -l /usr/bin/ls -r-xr-xr-x 1 root bin 27400 ene 24 2007 /usr/bin/lsLos ficheros que representan órdenes suelen pertenecer a
root
y tener permisos de ejecución para todos los usuarios, como se ve
en el ejemplo.
set
:
<gyermo@ENCINA>/usuarios/profes/gyermo$ set BASH=/usr/bin/bash BASH_ARGC=() BASH_ARGV=() BASH_LINENO=() BASH_SOURCE=() BASH_VERSINFO=([0]="3" [1]="00" [2]="16" [3]="1" [4]="release" [5]="sparc-sun-solaris2.10") BASH_VERSION="3.00.16(1)-release" CENTRO="Facultad de Ciencias" CENTRO2=Derecho COLUMNS=113 CUENTA="La cuenta asciende a: \$137,03\" [...]
<gyermo@ENCINA>/usuarios/profes/gyermo$ echo 1+1 1+1Bueno, en realidad estamos siendo algo injustos. Ya sabemos que esos unos son, en realidad, caracteres. Para que el ordenador realice la operación es necesario que le avisemos de que eso que le pasamos son números. Esto se logra así:
<gyermo@ENCINA>/usuarios/profes/gyermo$ echo $((1+1)) 2Podemos usar también variables:
<gyermo@ENCINA>/usuarios/profes/gyermo$ TRES=3 <gyermo@ENCINA>/usuarios/profes/gyermo$ echo $(($TRES*$TRES)) 9Las operaciones son iguales a las de C, salvo la exponenciación, que aquí se expresa con dos asteriscos seguidos (
**
).
También los operandos y el resultado están limitados a los
números enteros.
<gyermo@ENCINA>/usuarios/profes/gyermo$ cd CARTAS/ <gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ ls -l total 4 lrwxrwxrwx 1 gyermo profes 14 ago 19 19:40 ReyesMagos.txt -> SantaClaus.txt -rw-r--r-- 1 gyermo profes 186 ago 19 18:57 SantaClaus.txt <gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ rm ReyesMagos.txt <gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ cp SantaClaus.txt ReyesMagos.txt <gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ ls -l total 4 -rw-r--r-- 1 gyermo profes 186 ago 21 13:31 ReyesMagos.txt -rw-r--r-- 1 gyermo profes 186 ago 19 18:57 SantaClaus.txt <gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ chmod 600 ReyesMagos.txt SantaClaus.txt <gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ ls -l total 4 -rw------- 1 gyermo profes 186 ago 21 13:31 ReyesMagos.txt -rw------- 1 gyermo profes 186 ago 19 18:57 SantaClaus.txtEn el ejemplo, primero hemos vuelto a hacer que
ReyesMagos.txt
sea
un fichero normal y, luego, con una única orden chmod
hemos
cambiado los permisos de los dos ficheros de modo que los mantengamos alejados
de miradas indiscretas.
*
: este carácter casa con cualquier número
de caracteres de la cadena, incluso cero?
: este carácter casa con justo un carácter
de la cadena, aunque puede ser cualquiera[abc]
: esta expresión casa con cualquiera
de los caracteres que pongamos dentro de los corchetes,
en el ejemplo a
, b
o
c
. También se admiten rangos
de caracteres, separados por un guion. Por ejemplo,
[a-z]
casa con cualquier letra
minúscula del alfabeto inglés.[!abc]
o [^abc]
: igual que
el caso anterior, pero al
contrario. En el ejemplo, casa con cualquier
carácter que no sea ni a
, ni
b
, ni c
.
ls
:
<gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ ls -l total 4 -rw------- 1 gyermo profes 186 ago 21 13:31 ReyesMagos.txt -rw------- 1 gyermo profes 186 ago 19 18:57 SantaClaus.txt <gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ ls [!R]* SantaClaus.txt <gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ ls *.txt ReyesMagos.txt SantaClaus.txt <gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ ls *a?s* SantaClaus.txt <gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ ls *e?M* ReyesMagos.txt <gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ ls *a*s?t* ReyesMagos.txt SantaClaus.txt <gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ ls *s??a* *s??a*: No such file or directoryLas expresiones regulares pueden ser traducidas más o menos al lenguaje común, así la primera del ejemplo sería algo como lista todos los ficheros que no empiecen por R mayúscula. La segunda diría: lista todos los ficheros que acaben en
.txt
. Y así, sucesivamente.
ls
u
otra cualquiera, si la expresión regular casa, no llega nunca
a verla. El ordenador ya le ofrece el resultado de haberla
aplicado. Para que os convenzáis de ello, basta con impedir
al ordenador la expansión, metiendo la expresión entre
comillas:
<gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ ls -l total 4 -rw------- 1 gyermo profes 186 ago 21 13:31 ReyesMagos.txt -rw------- 1 gyermo profes 186 ago 19 18:57 SantaClaus.txt <gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ ls "*.txt" *.txt: No such file or directoryAl ponerlo entre comillas, el asterisco pierde su valor especial. El ordenador no expande la expresión regular y se la pasa tal cual a la orden
ls
. Como la orden no ve
ningún fichero que se llame *.txt
, pues da
un error.
<gyermo@ENCINA>/usuarios/profes/gyermo/DOCENCIA$ echo tema{1..10}.tex tema1.tex tema2.tex tema3.tex tema4.tex tema5.tex tema6.tex tema7.tex tema8.tex tema9.tex tema10.texLa segunda forma, cuando se trata de caracteres, estos van separados por comas y la shell construye una palabra por cada una de las posibilidades, como se puede comprobar en este ejemplo:
<gyermo@ENCINA>/usuarios/profes/gyermo/DOCENCIA$ echo para{lela,bólica,dójica,métrica}mente paralelamente parabólicamente paradójicamente paramétricamenteEs útil para, por ejemplo, borrar todos los ficheros de imágenes del directorio actual que empiecen por auto
rm auto*.{jpg,jpeg,gif,png}
).?
. Pero debemos
hacerlo justo después de haber ejecutado la orden, pues
si no, el valor que tenga la variable ya habrá sido
reescrito por la ejecución de cualquier otra orden.
<gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ ls -l total 4 -rw------- 1 gyermo profes 186 ago 21 13:31 ReyesMagos.txt -rw------- 1 gyermo profes 186 ago 19 18:57 SantaClaus.txt <gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ echo $? 0 <gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ ls -l PopeyeElMarino.txt PopeyeElMarino.txt: No such file or directory <gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ echo $? 2 <gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ echo $? 0La primera vez que imprimimos el valor devuelto nos da un 0, pues la ejecución anterior fue exitosa. La segunda vez, nos da un 2, pues el
ls
falló. Finalmente,
la tercera vez, nos devuelve 0, pues se refiere a la ejecución
anterior y la ejecución anterior fue el segundo
echo $?
que, evidentemente, no falló.
#include <stdio.h> int main(int argc,char *argv[]) {int i; if (argc==1) {fprintf(stderr,"Al programa %s no se le han pasado argumentos.\n", argv[0]); return 1;} for (i=1;i<argc;++i) fprintf(stderr,"El argumento %d es: \"%s\"\n", i, argv[i]); return 0; }Hacemos un directorio en nuestro directorio de conexión que se llame
ARGUMENTOS
. Dentro de él, editamos un fichero que
se llame argumentos.c
. Lo compilamos y ejecutamos varias
pruebas, con el resultado esperado:
<gyermo@ENCINA>/usuarios/profes/gyermo/ARGUMENTOS$ gcc argumentos.c -o argumentos <gyermo@ENCINA>/usuarios/profes/gyermo/ARGUMENTOS$ argumentos Al programa argumentos no se le han pasado argumentos. <gyermo@ENCINA>/usuarios/profes/gyermo/ARGUMENTOS$ echo $? 1 <gyermo@ENCINA>/usuarios/profes/gyermo/ARGUMENTOS$ argumentos Pepa El argumento 1 es: "Pepa" <gyermo@ENCINA>/usuarios/profes/gyermo/ARGUMENTOS$ echo $? 0 <gyermo@ENCINA>/usuarios/profes/gyermo/ARGUMENTOS$ argumentos ../CARTAS/* El argumento 1 es: "../CARTAS/ReyesMagos.txt" El argumento 2 es: "../CARTAS/SantaClaus.txt" <gyermo@ENCINA>/usuarios/profes/gyermo/ARGUMENTOS$ echo $? 0En el último caso, al ser el argumento una expresión regular, el ordenador lo ha sustituido antes de pasárselo a nuestro programa, como hemos visto.
#include <stdio.h> int main(int argc,char *argv[],char *environ[]) {int i; char **cpp; for (cpp=environ; *cpp!=NULL; ++cpp) fprintf(stderr,"Variable de entorno: %s\n", *cpp); if (argc==1) {fprintf(stderr,"Al programa %s no se le han pasado argumentos.\n", argv[0]); return 1;} for (i=1;i<argc;++i) fprintf(stderr,"El argumento %d es: \"%s\"\n", i, argv[i]); return 0; }No os olvidéis de volver a compilar antes de ejecutar el programa:
<gyermo@ENCINA>/usuarios/profes/gyermo/ARGUMENTOS$ gcc argumentos.c -o argumentos <gyermo@ENCINA>/usuarios/profes/gyermo/ARGUMENTOS$ argumentos Variable de entorno: MANPATH=:/usr/sfw/man:/usr/local/man:/opt/SUNWspro/man:/opt/SUNWste/license_tools/man:/usr/share/man:/opt/sfw/man Variable de entorno: LC_MONETARY=es_ES.ISO8859-1 Variable de entorno: TERM=xterm [...] Variable de entorno: LC_CTYPE=es_ES.ISO8859-1 Variable de entorno: ORACLE_HOME=/opt/oracle/product/10.2.0/Db_1 Variable de entorno: ENCINA=192.168.201.3 Variable de entorno: _=./argumentos Al programa argumentos no se le han pasado argumentos.Si repasáis la lista de variables de entorno que recibe el programa, veréis que no están las que definísteis más arriba. La razón es que el ordenador solamente pasa a los programas aquellas variables que habéis declarado como exportables (por así decirlo, que no son privadas vuestras). Si queréis hacer pública una variable de entorno lo tenéis que decir:
<gyermo@ENCINA>/usuarios/profes/gyermo/ARGUMENTOS$ export FACULTAD <gyermo@ENCINA>/usuarios/profes/gyermo/ARGUMENTOS$ argumentos Variable de entorno: MAJUELO=129.168.201.5 Variable de entorno: MANPATH=:/usr/sfw/man:/usr/local/man:/opt/SUNWspro/man:/opt/SUNWste/license_tools/man:/usr/share/man:/opt/sfw/man Variable de entorno: LC_MONETARY=es_ES.ISO8859-1 Variable de entorno: TERM=xterm [...] Variable de entorno: LC_CTYPE=es_ES.ISO8859-1 Variable de entorno: FACULTAD=Facultad de Ciencias Variable de entorno: ORACLE_HOME=/opt/oracle/product/10.2.0/Db_1 Variable de entorno: ENCINA=192.168.201.3 Variable de entorno: _=./argumentos Al programa argumentos no se le han pasado argumentos.A veces, resulta conveniente definir una variable solo para la ejecución de un programa concreto, sin que afecte a las definiciones de las variables de nuestra shell. En ese caso, puede usar la siguiente sintaxis:
<gyermo@ENCINA>/usuarios/profes/gyermo/ARGUMENTOS$ FACULTAD="Mi Facultad" argumentos Variable de entorno: MAJUELO=129.168.201.5 Variable de entorno: MANPATH=:/usr/sfw/man:/usr/local/man:/opt/SUNWspro/man:/opt/SUNWste/license_tools/man:/usr/share/man:/opt/sfw/man Variable de entorno: LC_MONETARY=es_ES.ISO8859-1 Variable de entorno: TERM=xterm [...] Variable de entorno: LC_CTYPE=es_ES.ISO8859-1 Variable de entorno: FACULTAD=Mi Facultad Variable de entorno: ORACLE_HOME=/opt/oracle/product/10.2.0/Db_1 Variable de entorno: ENCINA=192.168.201.3 Variable de entorno: _=./argumentos Al programa argumentos no se le han pasado argumentos. <gyermo@ENCINA>/usuarios/profes/gyermo/ARGUMENTOS$ echo $FACULTAD Facultad de Ciencias
Como se puede observar, una vez ejecutado el programa, la shell conserva el valor anterior que tuviera la variable.
#include <stdlib.h> char *getenv(const char *name);A la función se le pasa el nombre de la variable y devuelve su valor, o NULL en el caso de que la variable no esté definida.
LANG
:
Hola, ¿qué tal?
¿Qué pasa, majo?
What's up, man?
<gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ ls ReyesMagos.txt <gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ cp ReyesMagos.txt PapANoel.txt <gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ ls -l total 4 -rw-r--r-- 1 gyermo profes 186 ago 19 18:57 PapANoel.txt -rw-r--r-- 1 gyermo profes 186 ago 19 18:32 ReyesMagos.txtAunque, también, eso de Papá Noel suena un poco cursi. Mejor Santa Claus, que los tiempo de gloria franceses hace tiempo que pasaron. Lo renombramos:
<gyermo@ENCINA</usuarios/profes/gyermo/CARTAS$ mv PapANoel.txt SantaClaus.txt <gyermo@ENCINA</usuarios/profes/gyermo/CARTAS$ ls -l total 4 -rw-r--r-- 1 gyermo profes 186 ago 19 18:32 ReyesMagos.txt -rw-r--r-- 1 gyermo profes 186 ago 19 18:57 SantaClaus.txtComo veis, desde el punto de vista de Unix, renombrar y mover son una misma cosa. Resumiento, las órdenes de mantenimiento de ficheros son:
cp
(copy): copia el primer fichero en el segundomv
(move): mueve o renombra el primer ficherorm
(remove): borra un ficherodu -h
:
<gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ ls -l total 4 -rw-r--r-- 1 gyermo profes 186 ago 19 18:32 ReyesMagos.txt -rw-r--r-- 1 gyermo profes 186 ago 19 18:57 SantaClaus.txt <gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ du -h . 3K .3K son 3*1024 = 3072 bytes. Si cada fichero ocupa 186 bytes, esto es, los dos ficheros juntos ocupan 186+186 = 372 bytes, ¿dónde se han quedado los 3072-372 = 2700 bytes restantes? ¿Quién me está robando los bytes?
listar
como sustituto de
ls -l
podemos referirnos a esa orden mediante su
alias:
<gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ alias listar="ls -l" <gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ listar total 2 -rw-r--r-- 1 gyermo profes 186 ago 19 13:22 ReyesMagos.txt
--help
muy
fácilmente:
<gyermo@ENCINA</usuarios/profes/gyermo/CARTAS$ cat > --help Hola [[Pulsad CTRL+D]] <gyermo@ENCINA</usuarios/profes/gyermo/CARTAS$ ls -l total 4 [[...]] -rw-r--r-- 1 gyermo profes 5 sep 10 21:53 --help [[...]]Pero, ¿cómo lo borramos? ¿Y en Linux? Por borrar se entiende borrarlo completamente de modo que no aparezca en el listado del directorio. No basta con vaciar su contenido.
-i
de ls
:
<gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ ls -i 66225 ReyesMagos.txt 66223 SantaClaus.txtEs evidente que estos números serán diferentes cuando probéis vosotros el ejemplo, pues los datos de esos ficheros estarán en posiciones diferentes en la tabla de inodos de vuestro disco. En mi caso, el inodo 66225 se encuentran los datos de la carta a los Reyes Magos. Por su parte, en el inodo 66223 se encuentran los datos de la carta a Santa. Como una es copia exacta de la otra, la carta exactita está almacenada dos veces en el disco duro. ¿No podríamos hacer que los datos, al ser iguales, estuvieran una sola vez en el disco? Pues claro que sí. Lo que necesitamos es crear lo que se denomina un enlace duro. Para ello, borramos uno de los ficheros y lo enlazamos al otro:
<gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ rm ReyesMagos.txt <gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ ls -l total 2 -rw-r--r-- 1 gyermo profes 186 ago 19 18:57 SantaClaus.txt <gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ ln SantaClaus.txt ReyesMagos.txt <gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ ls -l total 4 -rw-r--r-- 2 gyermo profes 186 ago 19 18:57 ReyesMagos.txt -rw-r--r-- 2 gyermo profes 186 ago 19 18:57 SantaClaus.txtFijaos en que la orden
ln
primero lleva con qué
queremos enlazar y, luego, qué es lo que queremos enlazar.
Parecería más lógico que fuera al revés,
pero es así. Después de hechos los pasos anteriores,
la situación se parece mucho a la de antes. Tenemos dos
"ficheros", pero sabemos que los datos están una sola
vez. Veamos ahora los inodos y lo que ocupa nuestro directorio:
<gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ ls -i 66223 ReyesMagos.txt 66223 SantaClaus.txt <gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ du -h 2K .Hemos conseguido nuestro objetivo. Ahora el directorio, como los datos están compartidos, ocupa solamente 2K (1K para los datos, 1K para el directorio) en lugar de 3K. Si sois muy observadores, os daréis cuenta de que la salida del
ls -l
cuando teníamos dos
ficheros auténticos y ahora que tenemos dos enlaces, es ligeramente
distinta. El número misterioso que nos da ls
a
continuación de los permisos ha cambiado. La razón es que
ese número significa cuántos ficheros están compartiendo
los datos de ese. Antes los datos eran propios de cada fichero, por lo
que aparecía un 1, y ahora
están compartidos por dos ficheros, por lo que aparece un 2.
<gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ rm ReyesMagos.txt <gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ ls -l total 2 -rw-r--r-- 1 gyermo profes 186 ago 19 18:57 SantaClaus.txt <gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ ln -s SantaClaus.txt ReyesMagos.txt <gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ ls -l total 4 lrwxrwxrwx 1 gyermo profes 14 ago 19 19:40 ReyesMagos.txt -> SantaClaus.txt -rw-r--r-- 1 gyermo profes 186 ago 19 18:57 SantaClaus.txt <gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ ls -i 66225 ReyesMagos.txt 66223 SantaClaus.txt <gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ du -h 3K .Observad las siguientes diferencias:
-s
a ln
para pedir que el enlace sea simbólicols -l
marca el enlace simbólico no como
un fichero (-
), sino como enlace (l
)ls -l
muestra a dónde está apuntando el
enlace al final de la líneaSantaClaus.txt
).
y ..
, no está
permitido hacer enlaces duros a directorios. Enlaces blandos
sí se pueden hacer.
find
. Por ejemplo, si no recordamos dónde
pusimos nuestra carta a los Reyes Magos, le podemos pedir al ordenador que nos
la busque:
<gyermo@ENCINA>/usuarios/profes/gyermo$ find . -name ReyesMagos.txt -print find: cannot read dir ./PRUEBA: Permission denied ./CARTAS/ReyesMagos.txt <gyermo@ENCINA>/usuarios/profes/gyermo$ ls -ld PRUEBA d---r-xrwx 2 gyermo profes 512 ago 18 02:24 PRUEBANos ha dado un error, porque no puede entrar en el directorio
PRUEBA
,
lo que no es de extrañar, pues recordad que en una de las sesiones
le cambiamos los permisos, quitándonos todos, como se puede ver en
el ls
posterior.
find
es que admite expresiones regulares como nombre.
Pero debéis tener cuidado. Mirad el resultado de esta prueba,
cuyo objetivo era encontrar el fichero SantaClaus.txt
, pidiendo
todos aquellos que empiezan por S mayúscula:
<gyermo@ENCINA>/usuarios/profes/gyermo$ find . -name S* -print find: bad option SESION6 find: [-H | -L] path-list predicate-list <gyermo@ENCINA>/usuarios/profes/gyermo$ ls ARGUMENTOS MANTEJO backup PRIVADO bin PRUEBA CAJAFUERTE public_html CARTAS SESION3 chgrp.2 SESION6 gyermo-encina-2005-03.tar.gz TEMP mail¿Os dais cuenta de por qué falla? Como hemos explicado un poco más arriba, antes de que
find
siquiera llegue a empezar,
el ordenador ya ha sustituido las expresiones regulares que encuentre.
Resulta que S*
es una expresión regular que tiene
dos coincidencias: SESION3
y SESION6
. Después
de hacer las sustituciones, lo que recibe find
es:
find . -name SESION3 SESION6 -printEntiende que queremos buscar un fichero o directorio que se llame
SESION3
y no entiende qué pinta allí SESION6
y da el error. Para que haga lo que queremos, debemos proteger la
expresión regular con cualquiera de los métodos que
hemos visto:
<gyermo@ENCINA>/usuarios/profes/gyermo$ find . -name "S*" -print ./SESION3 ./SESION6 ./PRIVADO/SUTURNO ./PRIVADO/SUTURNO/SuTurno.log ./PRIVADO/SuTurno.log find: cannot read dir ./PRUEBA: Permission denied ./CARTAS/SantaClaus.txt
find
, junto con ls
es una de las órdenes
que más opciones tiene. Se pueden buscar ficheros no solamente
por el nombre, sino por tamaño, fecha, tipo, etc. y con los
ficheros encontrados no solamente se puede imprimir su ruta
-print
, sino, por ejemplo, ejecutar cualquier otra orden
sobre ellos. Esto, cuando conozcamos alguna orden más, nos va
a permitir realizar búsquedas basándonos en el contenido
de los ficheros. Por último, no es necesario partir del directorio
actual (.
); se puede usar cualquier otro. Para más
detalles, consultad, como siempre, la página de manual.
mlocate
de vuestros linux.
Si no os funciona, probad con locate
a secas. Si no,
es que el paquete no está instalado. La ventaja de estas herramientas
es que la búsqueda es casi instantánea.
/usuarios/profes/gyermo/CAJAFUERTE
se encuentra un fichero
secreto de nombre desconocido. Vuestra misión es, valiéndoos
de los medios conocidos hasta ahora, incluso consultando las páginas
de manual si es necesario, que lo localicéis.
cmp
y diff
. La primera de ellas devuelve
0 en el caso de que los ficheros sean iguales, 1, si son diferentes
y un número mayor, en el caso de haber un error. También
imprime el lugar en que se diferencian.
<gyermo@ENCINA>/usuarios/profes/gyermo$ cd CARTAS <gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ ls ReyesMagos.txt SantaClaus.txt <gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ cmp * <gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ echo $? 0 <gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ diff * <gyermo@ENCINA>/usuarios/profes/gyermo/CARTAS$ echo $? 0Veamos, ahora, a
diff
en su salsa. Que nos compare las
dos versiones del programa en C que hicimos en la
sección de interfaz con C de
más arriba.
<gyermo@ENCINA>/usuarios/profes/gyermo/ARGUMENTOS$ ls -l total 18 -rwxr-xr-x 1 gyermo profes 6552 ago 21 16:21 argumentos -rw-r--r-- 1 gyermo profes 291 ago 22 20:01 argumentos_viejo.c -rw-r--r-- 1 gyermo profes 414 ago 21 16:21 argumentos.c <gyermo@ENCINA>/usuarios/profes/gyermo/ARGUMENTOS$ diff argumentos_viejo.c argumentos.c 3,4c3,4 < int main(int argc,char *argv[]) < {int i; --- > int main(int argc,char *argv[],char *environ[]) > {int i; char **cpp; 5a6,8 > for (cpp=environ; *cpp!=NULL; ++cpp) > fprintf(stderr,"Variable de entorno: %s\n", *cpp); >Traducido a palabras que todos podamos entender,
diff
nos dice
que, para transformar un fichero en otro, hay que cambiar las líneas
3 y 4 del primero por las 3 y 4 del segundo y hay que añadir al
primero (y por tanto quitar al segundo) en la línea 5 las líneas
de la 6 a la 8 del segundo.
echo
unset
which
set
find
cmp
diff
cp
mv
rm
du
ln