2. Estructuras de control y órdenes de texto
Un script que solo ejecuta órdenes en línea recta sirve de poco: lo que lo hace útil es que decide (si el disco está lleno, avisa), repite (para cada usuario de la lista, crea la cuenta) y recibe datos de fuera (¿qué carpeta tengo que copiar?). Esta página te enseña las tres cosas, más las órdenes para trabajar con texto, que es lo que contienen los logs y los archivos de configuración.
1. Condicionales: if, elif, else y case
Sección titulada «1. Condicionales: if, elif, else y case»if / elif / else
Sección titulada «if / elif / else»#!/bin/bash# nota.sh · clasifica una nota que se pasa como parámetronota=$1if [ "$nota" -ge 9 ]; then echo "Sobresaliente"elif [ "$nota" -ge 5 ]; then echo "Aprobado"else echo "Suspenso"fi# nota.ps1 · clasifica una nota que se pasa como parámetroparam([int]$nota)if ($nota -ge 9) { Write-Host "Sobresaliente"} elseif ($nota -ge 5) { Write-Host "Aprobado"} else { Write-Host "Suspenso"}Las diferencias de sintaxis son sistemáticas:
| Bash | PowerShell | |
|---|---|---|
| Condición | Entre [ ] (con espacios) |
Entre paréntesis ( ) |
| Bloque | then … fi |
Llaves { } |
| «Si no, si» | elif |
elseif |
| Cierre | fi (y ; antes de then si va en la misma línea) |
} |
En Bash, if no evalúa «verdad», evalúa un código de salida: ejecuta la orden que hay después de if y, si devuelve 0, ejecuta el bloque then. [ … ] es, en realidad, una orden (también se puede escribir test …). Por eso funciona esto:
if grep -q "^$usuari:" /etc/passwd; then echo "El usuario $usuari existe"fiLas pruebas sobre archivos son imprescindibles en scripts de administración:
| Prueba | Bash | PowerShell |
|---|---|---|
| Existe (archivo o carpeta) | [ -e "$x" ] |
Test-Path $x |
| Es un archivo | [ -f "$x" ] |
Test-Path $x -PathType Leaf |
| Es una carpeta | [ -d "$x" ] |
Test-Path $x -PathType Container |
| Tiene contenido (tamaño > 0) | [ -s "$x" ] |
(Get-Item $x).Length -gt 0 |
| Se puede leer / escribir / ejecutar | -r, -w, -x |
— (se comprueba con permisos ACL) |
Para combinar condiciones, Bash admite && y || entre órdenes o corchetes ([ -f "$x" ] && [ -r "$x" ]) y, con el doble corchete [[ ]], también dentro de la condición: [[ -f $x && -r $x ]]. [[ ]] es propio de Bash (no vale en un sh estricto), no parte palabras, admite == con patrones ([[ $x == *.txt ]]) y =~ para expresiones regulares. En PowerShell: if ((Test-Path $x) -and ($n -gt 3)).
case (menús) y switch
Sección titulada «case (menús) y switch»Cuando una misma variable se compara con muchos valores, case es más limpio que una cadena de elif:
#!/bin/bashread -p "Opción (1-3): " opcase "$op" in 1) date +%F ;; 2) whoami ;; 3) echo "Adiós"; exit 0 ;; *) echo "Opción no válida" >&2; exit 2 ;;esac$op = Read-Host "Opción (1-3)"switch ($op) { "1" { Get-Date -Format "yyyy-MM-dd" } "2" { whoami } "3" { Write-Host "Adiós"; exit 0 } default { Write-Error "Opción no válida"; exit 2 }}Cada alternativa de case acaba en ;; y *) hace de «cualquier otro valor». El >&2 envía el mensaje a la salida de errores (sección 4).
2. Bucles
Sección titulada «2. Bucles»Un bucle repite un bloque. Hay dos familias: las que recorren una lista (for) y las que repiten mientras se cumpla una condición (while; until hace lo contrario: repite hasta que se cumple).
for fruita in poma pera taronja; do # recorre una lista echo "Fruta: $fruita"done
for i in {1..5}; do # intervalos: {inicio..final} echo "Vuelta $i"done
for ((i = 1; i <= 5; i++)); do # estilo C echo "$i"done
n=3while [ "$n" -gt 0 ]; do # mientras n > 0 echo "Quedan $n" n=$((n - 1))done
for f in *.txt; do # para cada archivo .txt de la carpeta echo "$f"doneforeach ($fruita in "poma", "pera", "taronja") { Write-Host "Fruta: $fruita" }
1..5 | ForEach-Object { Write-Host "Vuelta $_" }
for ($i = 1; $i -le 5; $i++) { Write-Host $i }
$n = 3while ($n -gt 0) { Write-Host "Quedan $n" $n--}
foreach ($f in Get-ChildItem *.txt) { Write-Host $f.Name }break sale del bucle y continue salta a la vuelta siguiente (igual en los dos shells). En PowerShell, dentro de un ForEach-Object, $_ es el elemento actual.
El bucle más útil en administración es leer un archivo línea a línea:
while read -r linia; do echo "Línea: $linia"done < usuaris.txtGet-Content .\usuaris.txt | ForEach-Object { Write-Host "Línea: $_" }El -r de read impide que Bash interprete las barras invertidas del texto. El < usuaris.txt del final redirige el archivo a la entrada del bucle (sección 4).
3. Parámetros y entrada de datos
Sección titulada «3. Parámetros y entrada de datos»Parámetros del script
Sección titulada «Parámetros del script»Un script reutilizable no lleva escritos los valores dentro: los recibe cuando se ejecuta (./copia.sh /home/ana).
| Bash | Significado |
|---|---|
$0 |
Nombre con el que se ha lanzado el script |
$1, $2, … $9 |
Primer, segundo… parámetro (a partir del 10, ${10}) |
$# |
Cuántos parámetros se han pasado |
"$@" |
Todos los parámetros, cada uno como palabra separada (es lo que debes usar en los bucles) |
shift |
Descarta $1 y desplaza el resto |
#!/bin/bashif [ $# -lt 1 ]; then echo "Uso: $0 nombre..." >&2 exit 1fifor nom in "$@"; do echo "Hola, $nom"doneecho "He saludado a $# personas"./saluda.sh Ana Luis "Maria Lopez" saluda a tres personas, porque las comillas hacen de «Maria Lopez» un solo parámetro.
PowerShell prefiere parámetros con nombre, declarados con un bloque param() al principio del script:
param( [Parameter(Mandatory)][string]$Carpeta, [int]$Dies = 7)Write-Host "Carpeta: $Carpeta · días: $Dies"Se ejecuta como .\copia.ps1 -Carpeta C:\Dades -Dies 3 (o .\copia.ps1 C:\Dades 3, por posición). Si falta -Carpeta, que es obligatorio, PowerShell la pide. Sin bloque param() los parámetros caen en el array $args ($args[0], $args.Count).
Preguntar al usuario
Sección titulada «Preguntar al usuario»read -p "¿Cómo te llamas? " nom # muestra el mensaje y guarda la respuestaread -s -p "Contraseña: " clau; echo # -s: no muestra lo que escribesread -r nom cognoms # «Ana Maria Lopez» → nom=Ana, cognoms="Maria Lopez"$nom = Read-Host "¿Cómo te llamas?"$clau = Read-Host "Contraseña" -AsSecureString # no muestra el texto; guarda un SecureStringSi una variable se lee con read, pásala siempre entre comillas cuando la uses. Y valida lo que se ha recibido: un script robusto comprueba que hay parámetros, que el archivo existe y que el número es un número, y en caso contrario termina con exit y un código distinto de 0.
4. Redirecciones y tuberías
Sección titulada «4. Redirecciones y tuberías»Cada programa tiene tres canales: la entrada estándar (0, el teclado), la salida estándar (1, la pantalla) y la salida de errores (2, también la pantalla, pero separada). Se pueden desviar:
| Queremos… | Bash | PowerShell |
|---|---|---|
| Salida a un archivo (sobrescribiendo) | orden > archivo |
orden > archivo |
| Añadir al final del archivo | orden >> archivo |
orden >> archivo |
| Solo los errores a un archivo | orden 2> errors.log |
orden 2> errors.log |
| Salida y errores juntos | orden >> a.log 2>&1 |
orden *>> a.log |
| Tirar la salida | orden > /dev/null |
orden > $null |
| Leer un archivo como entrada | orden < archivo |
Get-Content archivo | orden |
| Enviar la salida a un mensaje de error | echo "mal" >&2 |
Write-Error "mal" |
Una tubería (pipe, |) conecta la salida de una orden con la entrada de la siguiente. La gran diferencia es lo que viaja por ella: texto en Bash y objetos en PowerShell (por eso, en PowerShell, Sort-Object Length ordena por una propiedad sin tener que «cortar» columnas).
5. Órdenes de texto
Sección titulada «5. Órdenes de texto»Los scripts de administración pasan el día leyendo logs, listas de usuarios y archivos de configuración. Estas son las órdenes de Bash y sus equivalentes:
| Tarea | Bash | PowerShell |
|---|---|---|
| Buscar texto | grep "error" log.txt |
Select-String "error" log.txt |
| Ídem, sin distinguir mayúsculas | grep -i error log.txt |
(es el comportamiento por defecto) |
| Distinguir mayúsculas | (es el comportamiento por defecto) | Select-String ERROR log.txt -CaseSensitive |
| Líneas que no coinciden | grep -v INFO log.txt |
Select-String INFO log.txt -NotMatch |
| Primeras líneas | head -n 10 log.txt |
Get-Content log.txt -Head 10 |
| Últimas líneas | tail -n 10 log.txt |
Get-Content log.txt -Tail 10 |
| Seguir un archivo en directo | tail -f log.txt |
Get-Content log.txt -Tail 10 -Wait |
| Contar líneas | wc -l log.txt |
(Get-Content log.txt).Count |
| Una columna | cut -d: -f1 /etc/passwd |
Get-Content f | ForEach-Object { ($_ -split ':')[0] } |
| Ordenar | sort archivo |
Get-Content f | Sort-Object |
| Quitar repetidas y contarlas | sort f | uniq -c |
Get-Content f | Group-Object |
| Cambiar letras | tr 'a-z' 'A-Z' |
$text.ToUpper() |
| Sustituir texto | sed 's/vell/nou/g' f |
(Get-Content f) -replace 'vell','nou' |
Notas que evitan disgustos:
grepdistingue mayúsculas;Select-Stringno. Es una de las diferencias que más confunden.uniqsolo junta líneas consecutivas iguales: por eso se hacesortantes.sed 's/…/…/g'escribe el resultado por pantalla y no toca el archivo. Si añades-i(sed -i 's/vell/nou/g' f) sí lo modifica: haz una copia antes o usa-i.bak.-replacede PowerShell usa expresiones regulares y tampoco distingue mayúsculas.- Un
grepque no encuentra nada devuelve el código de salida 1, y eso no es un error del programa: es su manera de decir «no está». Por eso se puede poner directamente en unif.
Comprueba lo aprendido
Sección titulada «Comprueba lo aprendido»-
¿Cuál es el resultado de
[ "abc" -eq "abc" ]en Bash?Respuesta
Un error (
integer expression expected) y código de salida 2:-eqcompara números. Para texto se usa=:[ "abc" = "abc" ]. -
¿Por qué en un bucle
for nom in $@puede fallar con un parámetro como"Maria Lopez", y cómo se corrige?Respuesta
Sin comillas,
$@se parte en palabras y «Maria Lopez» se convierte en dos valores. Se corrige confor nom in "$@". -
¿Qué diferencia hay entre
orden > archivoyorden >> archivo?Respuesta
>crea o sobrescribe el archivo;>>añade al final sin borrar lo que ya había. -
Escribe en Bash y en PowerShell cómo contar las líneas de
access.logque contienen la palabra404.Respuesta
Bash:
grep "404" access.log | wc -l(ogrep -c "404" access.log). PowerShell:(Select-String "404" access.log).Count. -
sed 's/Windows/Linux/g' notes.txtno ha cambiado nada ennotes.txt. ¿Por qué?Respuesta
Porque
sedsin-isolo muestra el resultado por pantalla; el archivo original queda igual. Para cambiarlo hace faltased -i(mejor con copia:-i.bak) o redirigir la salida a un archivo nuevo.
Glosario
Sección titulada «Glosario»| Valencià | Castellano |
|---|---|
| estructura de control | estructura de control |
| condicional | condicional |
| bucle | bucle |
| paràmetre | parámetro |
| entrada estàndard / eixida estàndard | entrada estándar / salida estándar |
| eixida d’errors | salida de errores |
| redirecció | redirección |
| canonada (pipe) | tubería (pipe) |
| expressió regular | expresión regular |
| filtre de text | filtro de texto |
| bloc | bloque |
| línia d’ordres | línea de órdenes |
Esta web no usa cookies ni recoge datos personales. Tu navegador solo guarda, en tu propio equipo, algunas preferencias: el tema claro u oscuro, el estado del menú y, en los laboratorios, la última pestaña abierta y el tamaño de letra.