El propósito de estas FAQs (Frequently Asked Questions) es resolver las preguntas y dudas más frecuentes que aparecen cuando nos enfrentamos por vez primera a la programación del shell y a la biblioteca de hebras.

 

§         FAQ sobre la “Programación del tc-shell”

 

También podéis encontrar una relación de ejercicios resueltos y algunas propuestas de ejercicios para pensar el comportamiento “extraño” que en ocasiones nos parece que tiene el tc-shell.

§         Ejercicios resueltos

 

- - ¨¨¨ - -

 

FAQ de Sistemas Operativos (prácticas con tc-shell)

 

1.      Nombre de camino (archivo) absoluto y relativo

2.      Directorio actual y directorio de trabajo

3.      Directorio home

4.      Variables multipalabra

5.      Error frecuente “no muestra el resultado de la última línea del script”

6.      Modificación de las variables de entorno desde un programa

7.      Depuración de scripts

8.      Diferencia entre jobs y ps

9.      Cómo sacar por pantalla lo que se va a redireccionar a otra orden

10.  ¿Es posible construir scripts recursivos?

11.  Diferencia entre variable conmutador (set, unset) y variable con contenido

12.  Diferencia entre set y @

13.  Cómo ampliar una variable multipalabra con varios elementos más

14.  Uso del $

15.  Cómo recorrer una matriz mediante un foreach

16.  Uso de redirecciones

17.  Uso de órdenes Unix dentro de sentencias en los scripts

18.  Paso de argumentos en un alias

 

 

1.      Nombre de camino (archivo) absoluto y relativo

 

El nombre de cualquier archivo es único. Se dice que el nombre de un archivo es absoluto (pathname absoluto) cuando es completo, es decir, empieza en el directorio raíz /.  Por ejemplo: /dev/tty es un nombre de archivo absoluto.

 

El nombre es relativo (pathname relativo) si nos da la secuencia de búsqueda por el sistema de archivos empezando por el directorio actual (el nombre no empieza por /). Por ejemplo: dev/tty es un nombre relativo.

 

2.      Directorio actual y directorio de trabajo

 

Ambos se refieren al directorio en el que está trabajando el usuario. Cuando se usa la orden cd se está cambiando el directorio actual o de trabajo. Cualquier operación sobre archivos, si se da un pathname relativo, se realiza partiendo del directorio actual. Para saber cual es el directorio de trabajo actual basta con ejecutar la orden pwd.

 

3.      Directorio home

 

Es el directorio por defecto que tiene un usuario cuando se conecta al sistema. Siempre es el mismo, a no ser que lo cambie el administrador del sistema. Suele ser el directorio a partir del cual el usuario crea su propia estructura de directorios y archivos. Para saber cual es el directorio home basta con ejecutar: echo $home o echo $HOME

 

4.      Variables multipalabra

 

Las variables multipalabra se crean con la orden set. Por ejemplo, vamos a crear una variable multipalabra con cuatro elementos: : set conjunto = (1 2 3 4). Para acceder a cada uno de los elementos, basta poner conjunto[1]. Son matrices cuyos elementos comienzan siempre en la posición 1 (no en el 0 como las matrices en C).

 

5.      Error frecuente “no muestra el resultado de la última línea del script”

 

Este problema viene porque después de la última línea dentro del programa shell o script debe existir un salto de línea (pulsar enter antes de cerrar el archivo que contiene el script).

 

6.      Modificación de las variables de entorno desde un programa

 

Para que las modificaciones de las variables de entorno tengan efecto en el shell donde se está ejecutando un script, debemos utilizar la orden source junto con el nombre del programa o script.

 

7.      Depuración de scripts

 

Podemos usar las opciones –v y –x junto con la orden tcsh para comprobar el funcionamiento de un script. Con la opción –v se muestra en pantalla la secuencia de las ordenes que se ejecutarían sin hacer sustituciones (no se ejecuta nada) y con –x se mostrarían las ordenes antes de ser ejecutadas.

 

8.      Diferencia entre jobs y ps

 

jobs lista los trabajos activos (en segundo plano y suspendidos) del usuario y su estado de ejecución. ps muestra información diversa sobre los procesos activos en el sistema (por defecto sólo los de la sesión del usuario que ejecuta la orden): su PID, su PPID, su tiempo de CPU consumido, etc.

 

9.      Cómo sacar por pantalla lo que se va a redireccionar a otra orden

 

Para ello se usa la orden tee que bifurca lo que le llega de la entrada estándar a la salida estándar y a un archivo que se le ponga como argumento. Ejemplo:

 

            ls | sort | tee listaOrdenada

 

en listaOrdenada  tendremos la lista de archivos del directorio actual ordenada según el código ASCII.

 

10. ¿Es posible construir scripts recursivos?

 

Si, no hay ningún problema.

 

11. Diferencia entre variable conmutador (set, unset) y variable con contenido

 

Cuando ejecutamos set var, la variable var ya existe en el entorno donde nos encontremos, si queremos que no exista debemos usar unset var. Esto nos es útil cuando sólo necesitamos tener una variable como conmutador (o existe o no existe). A diferencia de esto, si necesitamos que tome un valor concreto debemos asignarle un valor, por ejemplo set var = 3

 

12. Diferencia entre set y @

 

La @ la usamos para expresar que la variable que definimos puede almacenar un valor entero o el resultado de una expresión matemática. Si usamos set para este tipo de variables dará un error.

 

13. Cómo ampliar una variable multipalabra con varios elementos más

 

En este ejemplo añadimos el carácter “a” a la variable multipalabra var. Nótese que se está redefiniendo.

 

            set var = (a $var)

 

 

      @permisoej = -x $i

      if($esta) then

            if($permisoej) then

                  set listadir = ($listadir $i)

            endif

      endif

end

 

echo Los directorios que existen en $argv[1] y

echo tenemos permiso de ejecución son:

echo $listadir

 

 

 

EJERCICIO 23. Deseamos explorar la historia para tomar la ultima instrucción mv (que suponemos que siempre se ha proporcionado en la forma mv archivo1 archivo2) y proporcionar la orden contraria mv archivo2 archivo1 para volver nombrar al archivo con su nombre original. Escriba una única orden con alusiones al mecanismo de sustitución de la historia para conseguir lo anterior:

 

 

 

mv  !mv:2  !mv:1

 

# Usamos las referencias 2 y 1 como constantes numericas

# porque partimos de la certeza de que la orden mv que

# se encuentra solo tiene dos argumentos.

 

 

EJERCICIO 24. Explique la razón de que se produzcan las siguientes situaciones presuntamente incoherentes.

 

 

* (sort <f)>f øporque da vacio f?

 

 

* Comportamiento curioso:

      ls

      a1 a2 a3

      ls | wc -l

      3

 

* Tenemos varios archivos que empiezan por m, y la orden ls m* nos dice que no hay ninguno; ¿Porqué puede ser?

 

* Explicar cómo podemos con cat visualizar el contenido de un archivo

llamado b*

 

* Muy curioso:

 

cd d1 | ls

no se realiza el cambio de directorio.

 

 

SOBRE LA BUENA EJERCITACION DE LOS MENSAJES DE ERROR:

 

* Establezca la variable echo para mostrar cada instrucción con las sustituciones resueltas antes de su ejecución, y explique qué se produce al ejecutarse la siguiente orden:

 

` cat >> f1`  echo hola

 

* Dentro de una definición de alias estamos haciendo referencia al primer argumento. Explicar qué diferencias hay entre \!1 y \!:1

 

* Explicar porque funciona mal la orden siguiente

 

set va1= 4

 

* Hemos creado un alias de la siguiente manera, con la idea de que muestre los archivos hijos del directorio actual que empiezan por . y terminan en el literal que pasamos como primera argumento. Explicar porqué funciona mal, y corregirlo.

 

alias ocultos "ls -a .*!1"

 

 

* Queríamos construir una línea de órdenes formada por dos ordenes echo separadas por punto y coma, pero este carácter ha sido olvidado, habiendo quedado finalmente

 

echo hola > arc1 echo adios > arc2

 

explicar el sentido del mensaje de error que se proporciona en este caso.

 

* Para dar valores con nombres de archivos a una variable multipalabra hemos puesto

 

set archivos = (datos02, deudas03, atrasos01, fondos04)

 

y después queremos visualizarlos con

 

cat $archivos[1]

 

siendo así que existe el archivo datos02, ¿por qué da error la orden anterior?

 

* Explicar por qué no funciona correctamente el siguiente programa:

 

set dias = ( lu ma mi ju vi sa do)

 

set v = $dias[1-5]

 

foreach i ($v)

echo otro dia laborable $i

end

 

* Depure el siguiente programa:

 

set a = (a b c d)

echo $a[2]

set $a[2] = 55

echo $a[2]

 

* Depure el siguiente programa:

 

set a = (a b c d)

echo $a [2]

 

* Explicar porque da error esto

 

set v = (a b c)

set v

echo $v[2]

 

* De la reflexión anterior se concluiría que al hacer set de variable multipalabra (orden set v del ejemplo anterior) ésta queda a valor nulo.

En el ejemplo siguiente se ha puesto la orden set $v, ¿Cómo es que acaba

poniéndose a nulo el valor de la variable a?

 

set a = (rojo azul negro)

set v = (a b c)

set $v

echo $v

echo $a

 

Puede probar a ejecutar lo anterior con la variable echo establecida.

 

* Encontrar donde esta el error en los siguiente:

 

      set opcion = $<

      switch (opcion)

            case 1: crear

            breaksw

            case 2: eliminar

            breaksw

            default:

            echo otros

           

      endsw

 

###### ejemplo poco afortunado el siguiente **** Queremos construir un

alias que llame a ls para que nos muestre la lista de los archivos hijos del directorio actual que empiezan por el literal

que proporcionamos en el primer argumento, es decir:

 

alias busca "ls \!:1*"

 

¿Por qué da error? ¿cómo podemos solucionarlo?

 

Una respuesta aunque parcial es que es necesario englobar la referencia al

primer argumento entre llaves para que no tome 1* como indicación de

argumentos desde 1 hasta el penúltimo. Asi pues la mejoraríamos así:

 

alias busca "ls {\!:1}*"

 

Pero ahora nos situamos en la siguiente secuencia:

 

ls g*

gatos gatas gatito1

busca gat

gatos gatas gatito1

cp gatito1 gatito2

ls g*

gatos gatas gatito1 gatito2

busca gat

gatos gatas gatito1

 

¿Por qué no aparece gatito2 en la última llamada a busca gat? (si que aparece, es que se resuelve el patrón antes de pasar a ls y claro este recibe como argumentos la lista de la resolución del patrón y puede continuar.

 

* Hemos definido un alias de nombre findname que llamara a find, busca en

el directorio que pasamos como primer argumento los archivos que cumplen

el patron que se pasa como segundo argumento:

 

alias findname "find  \!:1 - name \!:2 - print"

 

Explique porqué da error y cómo se puede solucionar.

 

* Tenemos un alias definido asi:

 

alias mialias "echo `ps|grep  \!

 

tal vez poner un   alias buscar = "set a= `ls

 

* tenemos un alias asi

 

alias af "find \!:1 -name \!:2 -print"

 

y lo ejecutamos así

 

af uno l*

 

Situémonos en el caso de que existen dentro del directorio uno un conjunto

de archivos que empiezan por l, ¿por qué da error la llamada anterior?

 

* Explicar porqué funciona mal lo siguiente:

 

echo Teclee una respuesta. Desea continuar? (Escriba S/N)

echo $<

 

* Explicar las diferencias entre

 

Alias pru “echo ¡1”

Alias pru “echo ¡:1”

Alias pru “echo \!1”

Alias pru  “echo  \!:1”

 

 

 

EJERCICIO .

 

En el directorio de trabajo tenemos una serie de archivos que comienzan por F y a continuación tienen un campo de dos caracteres numérico desde 00 hasta cierto valor (como mucho 99). Ej:

 

                        F00, F03, F09, F25, F01, F23

 

Deseamos asignar a una variable llamada nuevonombre el literal F<n> donde <n> es el numero mas alto de los ficheros encontrados mas uno. Recordamos que ha de tener dos digitos, es decir,  si es menor que 10 su primer digito debe ser un cero.

 

 

set nuevonombre = `ls -l F?? | tail -1 | cut -c56-57`

 

@ nuevonombre = $nuevonombre + 1

 

if ($a <= 9 ) then

            set nuevonombre= F0$nuevonombre

else

            set nuevonombre = F$nuevonombre

endif

echo $nuevonombre