리눅스 명령행 인자: 명령어 옵션과 따옴표, 옵션 끝 표시, $1, $# 받기

Entorno de pruebaFamilia RHELAlmaLinux 9.8bash 5.1Cuenta root
Shell$1$#--

Los argumentos de línea de comandos de Linux (command-line argument) son los valores que se pasan a un programa escribiéndolos después del nombre del comando, separados por espacios. Al pasar opciones, comillas, comodines y -- a un script de prueba que muestra tal cual los argumentos que recibe en un servidor AlmaLinux 9, vimos que quien separaba los argumentos era la shell y quien leía las opciones era cada comando.

La salida de abajo es exactamente la que se obtuvo con bash 5.1 en la cuenta root de un servidor AlmaLinux 9.8. Los scripts de prueba y los archivos de ejemplo se crearon en una carpeta de trabajo aparte, y la ruta /home/user/www es un valor de ejemplo.

1️⃣ ¿Qué son los argumentos de línea de comandos en Linux?

Si en la línea de comandos escribes algo como [comando arg1 arg2], la shell separa las palabras por los espacios. La primera palabra es el programa que se ejecuta, y las demás se pasan en orden a ese programa como sus argumentos.

Para ver los argumentos que llegan, creamos args.sh en la carpeta de trabajo. $0 contiene el nombre con el que se ejecutó, $# el número de argumentos, y de $1 en adelante los argumentos en orden. Los corchetes se añadieron para que se vea dónde empieza y termina cada argumento.

#!/bin/bash
echo "\$0 = $0"
echo "\$# = $#"
i=1
for a in "$@"; do
  echo "\$$i = [$a]"
  i=$((i+1))
done

Dimos permiso de ejecución al script y lo ejecutamos con tres palabras: a, b y c.

./args.sh a b c
$0 = ./args.sh
$# = 3
$1 = [a]
$2 = [b]
$3 = [c]

Las tres palabras entraron en $1, $2 y $3, y $# fue 3. Si lo ejecutas escribiendo el nombre del script después de bash, $0 contiene el nombre tal como lo escribiste, args.sh.

bash args.sh a b c
$0 = args.sh
$# = 3
$1 = [a]
$2 = [b]
$3 = [c]

Solo $0 cambió a args.sh; los tres argumentos y el número fueron los mismos que antes.

2️⃣ Argumentos de línea de comandos y opciones de comandos

Los comandos de Linux suelen escribirse en el orden [comando -opción argumento]. Las opciones cambian cómo actúa el comando, y los argumentos indican los archivos, rutas o valores con los que trabaja.

ls -l /home/user/www

Para la shell, -l también es solo un argumento. Al pasar las mismas palabras a args.sh, -l entró en $1 y la ruta en $2.

./args.sh -l /home/user/www
$0 = ./args.sh
$# = 2
$1 = [-l]
$2 = [/home/user/www]

Quien lee -l como opción es ls. Por eso la misma letra significa cosas distintas en cada comando: -n en head fija el número de líneas que se muestran, y -n en ls muestra el propietario como número en lugar de nombre.

Algunas opciones toman como valor propio la palabra que va justo después. En el comando find, -type usa f y -name usa "*.txt" como su valor; un valor que acompaña así a una opción se llama argumento de opción.

find . -type f -name "*.txt"

En este comando, el . del principio es un argumento que no acompaña a ninguna opción e indica la carpeta donde empieza la búsqueda.

3️⃣ Formatos de las opciones de comandos en Linux

Las opciones cortas empiezan con un guion y son de una sola letra, y se pueden escribir varias juntas. Primero mostramos la carpeta site de la carpeta de trabajo con [ls -l -a].

ls -l -a site
total 8
drwxr-xr-x 3 root root  52 Oct 28 16:00 .
drwxr-xr-x 3 root root 137 Oct 29 01:20 ..
-rw-r--r-- 1 root root  17 Oct 28 16:00 .htaccess
drwxr-xr-x 2 root root  23 Oct 28 16:00 css
-rw-r--r-- 1 root root  14 Oct 28 16:00 index.html

Después la comparamos con diff con la salida de [ls -la], que junta las dos letras.

diff <(ls -l -a site) <(ls -la site) && echo same
same

Las dos salidas no se diferenciaron en un solo carácter. Las opciones largas empiezan con dos guiones y se escriben como palabras; --all de ls es la misma opción que -a, así que [ls -l --all site] dio también el mismo resultado.

Las opciones largas se aceptan aunque escribas solo el principio, siempre que coincida con una sola opción. --al coincidía con dos opciones, --all y --almost-all, así que ls no mostró la lista y terminó con el código de salida 2.

ls --al site
ls: option '--al' is ambiguous; possibilities: '--all' '--almost-all'
Try 'ls --help' for more information.

Las opciones que reciben un valor pueden escribirse de varias formas. Al mostrar las dos primeras líneas de a.txt con head, la opción corta puede llevar el valor pegado, como [-n2].

head -n2 a.txt
alpha
beta

La opción larga une el valor con un signo igual, como [--lines=2].

head --lines=2 a.txt
alpha
beta

Las cuatro formas, incluidas [-n 2] y [--lines 2] separadas por espacio, mostraron las dos líneas alpha y beta.

ls, head y cat leen sus opciones con la función getopt_long de la biblioteca de C. Al revisar los tres archivos de programa con strings, todos contenían el nombre de esta función.

Para comprobar las mismas reglas desde la shell se usa el comando getopt de util-linux. Las opciones cortas se escriben después de -o y las largas después de -l; los dos puntos detrás de una letra indican que la opción recibe un valor.

getopt -o lan: -l all,lines: -- -la -n 2 --all a.txt
 -l -a -n '2' --all -- 'a.txt'

El -la escrito junto se dividió en -l y -a, y -n 2 se agrupó como -n con el valor 2. a.txt, que no es una opción, se movió al final, después de --.

4️⃣ Argumentos entre comillas y comodines

Un nombre de archivo con espacios debe ir entre comillas para pasarse como un solo argumento.

./args.sh "my file.txt" report.txt
$0 = ./args.sh
$# = 2
$1 = [my file.txt]
$2 = [report.txt]

Sin comillas, my y file.txt se separaron y $# pasó a ser 3. Si lo pasas así a ls o cat, buscarán dos archivos llamados my y file.txt.

./args.sh my file.txt report.txt
$0 = ./args.sh
$# = 3
$1 = [my]
$2 = [file.txt]
$3 = [report.txt]

La shell convierte los comodines en nombres de archivo antes de que el programa los reciba. Al pasar *.txt en la carpeta de trabajo, entraron por orden alfabético los cuatro archivos que terminan en .txt.

./args.sh *.txt
$0 = ./args.sh
$# = 4
$1 = [a.txt]
$2 = [b.txt]
$3 = [my file.txt]
$4 = [report.txt]

El "*.txt" entre comillas no lo cambió la shell y quedó como un solo argumento, letra por letra. En opciones como -name de find, donde el programa compara el patrón por sí mismo, se pasa así, entre comillas.

./args.sh "*.txt"
$0 = ./args.sh
$# = 1
$1 = [*.txt]

Unas comillas vacías también se pasan como un argumento vacío. Al ejecutar [./args.sh '' b], $# fue 2 y $1 quedó vacío.

5️⃣ Fin de las opciones de un comando (--)

Un argumento que empieza con guion, como un archivo llamado -n, el comando lo lee como opción. Al ejecutar [ls -n] en la carpeta dash, que solo contiene ese archivo, ls tomó -n no como nombre de archivo sino como la opción de salida numérica y mostró la lista de la carpeta.

ls -n
total 4
-rw-r--r-- 1 0 0 10 Oct 28 16:00 -n

Los argumentos escritos después de -- no se leen como opciones aunque empiecen con guion. [ls -- -n] mostró solo el nombre de archivo -n.

ls -- -n
-n

Dentro de un mismo comando, los mismos caracteres se leen distinto antes y después de --. Al pasar -n dos veces a cat, el primer -n se leyó como la opción de números de línea y el -n después de -- como nombre de archivo, y salió el contenido del archivo con números de línea.

cat -n -- -n
     1	dash file

También se puede añadir la ruta y escribir ./-n; en ese caso el argumento no empieza con guion y se lee como el mismo archivo -n.

Leer -- como el fin de las opciones también es una regla del lado del comando. Al pasarlo a args.sh, que no lee opciones, -- también entró tal cual en $1.

./args.sh -- -a
$0 = ./args.sh
$# = 2
$1 = [--]
$2 = [-a]

Las convenciones de utilidades de POSIX establecen que el primer -- que no sea argumento de opción se acepta como el fin de las opciones. Por eso, en los comandos que siguen estas convenciones, los nombres de archivo que empiezan con - se escriben después de --.

6️⃣ Recibir argumentos de línea de comandos en un script de shell

Un script de shell lee los argumentos que recibe mediante parámetros posicionales y parámetros especiales. El main(int argc, char *argv[]) de un programa en C recibe los mismos argumentos, así que puestos uno al lado del otro quedan así.

ParámetroValor que contieneFunción main de C
$0Nombre del script ejecutadoargv[0]
$1 ~ $9Del primer al noveno argumentoargv[1] ~ argv[9]
${10}Desde el décimo argumento, entre llavesargv[10]
$#Número de argumentos, sin contar $0argc - 1
"$@"Todos los argumentos, cada uno por separadoDe argv[1] hasta el final
"$*"Todos los argumentos unidos en uno con espacios—

Un programa en Python recibe los mismos argumentos como la lista sys.argv. Al pasar tres argumentos con [python3 -c], my file.txt entre comillas entró en un solo elemento de la lista, y en el primer elemento entró -c.

python3 -c 'import sys; print(sys.argv)' a "my file.txt" -l
['-c', 'a', 'my file.txt', '-l']

"$@" y "$*" dan resultados distintos cuando van entre comillas dobles. Para ver la diferencia, creamos star.sh, que muestra las dos formas una tras otra.

#!/bin/bash
echo 'with "$@"'
printf '  [%s]\n' "$@"
echo 'with "$*"'
printf '  [%s]\n' "$*"

Ejecutamos star.sh con tres argumentos: a, "b c" y d.

./star.sh a "b c" d
with "$@"
  [a]
  [b c]
  [d]
with "$*"
  [a b c d]

"$@" pasó los tres argumentos por separado, y "$*" los unió con espacios y los pasó como uno solo.

Por eso, para pasar a otro comando los argumentos recibidos sin cambios, se usa "$@".

shift descarta $1 y adelanta una posición los argumentos restantes. Se usa en scripts que leen primero una opción y tratan el resto como una lista de archivos.

Creamos shift.sh, que muestra $1 y $# antes y después de shift.

#!/bin/bash
echo "before shift: \$1 = $1, \$# = $#"
shift
echo "after shift:  \$1 = $1, \$# = $#"

Ejecutamos shift.sh con tres argumentos: -v, a.txt y b.txt.

./shift.sh -v a.txt b.txt
before shift: $1 = -v, $# = 3
after shift:  $1 = a.txt, $# = 2

A partir del décimo argumento se usan llaves, como en ${10}. Creamos ten.sh, que muestra $10 y ${10} uno al lado del otro.

#!/bin/bash
echo "\$10 = $10"
echo "\${10} = ${10}"

Pasamos a ten.sh 11 argumentos, de la a a la k.

./ten.sh a b c d e f g h i j k
$10 = a0
${10} = j

$10 salió como a0, es decir, $1 seguido de un 0, y ${10} salió como el décimo argumento, j.

🔲 Simulador de argumentos de línea de comandos

En el simulador de abajo puedes pasar comillas, comodines y -- a args.sh, y escribir tú mismo comandos para ver cómo leen las opciones ls y getopt y cómo reciben los argumentos star.sh y shift.sh.

Simulador de argumentos de línea de comandosbash 5.1
[root@server work]#
Es un servidor AlmaLinux virtual que funciona solo en tu navegador; args.sh muestra los argumentos recibidos con su número, y ↑↓ recupera los comandos que usaste antes.

🔢 FAQ & contenido recomendado

El límite de la longitud total de argumentos y variables de entorno se consulta con [getconf ARG_MAX]; en el servidor AlmaLinux 9.8 era de 2097152 bytes. Si se supera, el programa no se ejecuta y aparece el error [Argument list too long]. Cuando hay muchísimos archivos, no los pases todos de una vez con un comodín; repártelos con -exec de find o con xargs.

Un argumento (argument) es el valor que realmente se pasa al ejecutar un comando, y un parámetro (parameter) es el nombre que recibe ese valor del lado receptor. En un script de shell, los parámetros posicionales como $1 y $2 reciben los argumentos pasados.

getopts, integrado en bash, lee una por una las opciones cortas como -v. No lee opciones largas, así que para aceptar también opciones largas como --verbose, primero ordena los argumentos con el comando getopt usado arriba.

ℹ️ Aviso de afiliados
El contenido de este sitio incluye enlaces de afiliado. Cuando un visitante compra un producto o servicio a través de uno de ellos, el sitio recibe una comisión del vendedor. El importe que paga el comprador(baja durante las promociones ↓)no aumenta. Los precios, descuentos y existencias publicados corresponden al momento de redacción y pueden variar, así que confírmalos con el vendedor antes de comprar. Los productos se eligen y evalúan con criterios propios, y las comisiones no influyen en el orden ni en el contenido de las reseñas.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Demuestra que eres humano: 2   +   8   =