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

Ambiente de testeFamília RHELAlmaLinux 9.8bash 5.1conta root
Shell$1$#--

Os argumentos de linha de comando do Linux (command-line argument) são valores passados a um programa escrevendo-os depois do nome do comando, separados por espaços. Ao passar opções, aspas, curingas e -- para um script de teste que mostra exatamente os argumentos que recebe em um servidor AlmaLinux 9, vimos que quem separava os argumentos era o shell e quem lia as opções era cada comando.

A saída abaixo é exatamente a obtida com bash 5.1 na conta root de um servidor AlmaLinux 9.8. Os scripts de teste e os arquivos de exemplo foram criados em uma pasta de trabalho à parte, e o caminho /home/user/www é um valor de exemplo.

1️⃣ O que são argumentos de linha de comando no Linux?

Quando você escreve algo como [comando arg1 arg2] na linha de comando, o shell separa as palavras pelos espaços. A primeira palavra vira o programa a ser executado, e as demais são passadas em ordem a esse programa como argumentos.

Para ver os argumentos recebidos, criamos o args.sh na pasta de trabalho. $0 guarda o nome usado para executá-lo, $# a quantidade de argumentos, e de $1 em diante os argumentos em ordem. Os colchetes foram colocados para mostrar onde cada argumento começa e termina.

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

Demos permissão de execução ao script e o executamos com três palavras: a, b e c.

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

As três palavras foram para $1, $2 e $3, e $# foi 3. Se você executar o script escrevendo o nome dele depois de bash, $0 guarda o nome exatamente como foi escrito, args.sh.

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

Só $0 mudou para args.sh; os três argumentos e a quantidade ficaram iguais ao resultado anterior.

2️⃣ Argumentos de linha de comando e opções de comando

Os comandos do Linux costumam ser escritos na ordem [comando -opção argumento]. As opções mudam o modo como o comando funciona, e os argumentos definem os arquivos, caminhos ou valores com que ele trabalha.

ls -l /home/user/www

Para o shell, -l também é só um argumento. Ao passar as mesmas palavras para o args.sh, -l foi para $1 e o caminho para $2.

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

Quem lê -l como opção é o ls. Por isso a mesma letra tem significados diferentes em cada comando: -n no head define quantas linhas mostrar, e -n no ls mostra o dono como número em vez de nome.

Algumas opções pegam como valor próprio a palavra logo depois delas. No comando find, -type usa f e -name usa "*.txt" como valor; um valor ligado a uma opção dessa forma se chama argumento de opção.

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

Neste comando, o . do começo é um argumento que não pertence a nenhuma opção e define a pasta onde a busca começa.

3️⃣ Formatos das opções de comandos do Linux

Opções curtas começam com um hífen e têm uma só letra, e várias podem ser escritas juntas. Primeiro listamos a pasta site da pasta de trabalho com [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

Em seguida comparamos com diff a saída de [ls -la], que junta as duas letras.

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

As duas saídas não diferiram em nenhum caractere. Opções longas começam com dois hífens e são escritas como palavras; --all do ls é a mesma opção que -a, então [ls -l --all site] também deu o mesmo resultado.

Opções longas são aceitas mesmo que você escreva só o começo, desde que ele corresponda a uma única opção. --al correspondia a duas opções, --all e --almost-all, por isso o ls não mostrou a lista e terminou com o código de saída 2.

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

Opções que recebem valor podem ser escritas de várias formas. Ao mostrar as duas primeiras linhas de a.txt com head, a opção curta pode ter o valor colado, como em [-n2].

head -n2 a.txt
alpha
beta

A opção longa liga o valor com um sinal de igual, como em [--lines=2].

head --lines=2 a.txt
alpha
beta

As quatro formas, incluindo [-n 2] e [--lines 2] separadas por espaço, mostraram as duas linhas alpha e beta.

ls, head e cat leem suas opções com a função getopt_long da biblioteca C. Ao examinar os três arquivos de programa com strings, todos tinham o nome dessa função.

Para conferir as mesmas regras no shell, usa-se o comando getopt do util-linux. Depois de -o vêm as opções curtas e depois de -l as longas; dois-pontos depois de uma letra indicam que a opção recebe um valor.

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

O -la escrito junto foi separado em -l e -a, e -n 2 foi agrupado como -n com o valor 2. a.txt, que não é opção, foi movido para o fim, depois de --.

4️⃣ Argumentos entre aspas e curingas

Um nome de arquivo com espaço precisa estar entre aspas para ser passado como um único argumento.

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

Sem aspas, my e file.txt foram separados e $# passou a 3. Se você passar assim para ls ou cat, eles vão procurar dois arquivos chamados my e file.txt.

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

Os curingas são trocados por nomes de arquivos pelo shell antes de o programa recebê-los. Ao passar *.txt na pasta de trabalho, entraram em ordem alfabética os quatro arquivos que terminam em .txt.

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

O "*.txt" entre aspas não foi trocado pelo shell e virou um único argumento, letra por letra. Em opções como o -name do find, em que o próprio programa compara o padrão, ele é passado assim, entre aspas.

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

Aspas vazias também são passadas como um argumento vazio. Ao executar [./args.sh '' b], $# foi 2 e $1 ficou vazio.

5️⃣ Fim das opções do comando (--)

Um argumento que começa com hífen, como um arquivo chamado -n, é lido pelo comando como opção. Ao executar [ls -n] na pasta dash, que contém só esse arquivo, o ls tomou -n não como nome de arquivo, mas como a opção de saída numérica, e listou a pasta.

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

Argumentos escritos depois de -- não são lidos como opções, mesmo que comecem com hífen. [ls -- -n] mostrou só o nome de arquivo -n.

ls -- -n
-n

Dentro de um mesmo comando, os mesmos caracteres são lidos de forma diferente antes e depois de --. Ao passar -n duas vezes para o cat, o primeiro -n foi lido como a opção de números de linha e o -n depois de -- como nome de arquivo, e o conteúdo do arquivo saiu com números de linha.

cat -n -- -n
     1	dash file

Também dá para acrescentar o caminho e escrever ./-n; nesse caso o argumento não começa com hífen e é lido como o mesmo arquivo -n.

Ler -- como o fim das opções também é uma regra do lado do comando. Ao passá-lo para o args.sh, que não lê opções, -- também foi para $1 sem mudanças.

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

As Convenções de Utilitários do POSIX determinam que o primeiro -- que não seja argumento de opção seja aceito como o fim das opções. Por isso, nos comandos que seguem essas convenções, nomes de arquivos que começam com - são escritos depois de --.

6️⃣ Receber argumentos de linha de comando em um script shell

Um script shell lê os argumentos recebidos por meio de parâmetros posicionais e parâmetros especiais. O main(int argc, char *argv[]) de um programa em C recebe os mesmos argumentos; colocando os dois lado a lado, fica assim.

ParâmetroValor que contémFunção main em C
$0Nome do script executadoargv[0]
$1 ~ $9Do primeiro ao nono argumentoargv[1] ~ argv[9]
${10}A partir do décimo argumento, entre chavesargv[10]
$#Quantidade de argumentos, sem contar $0argc - 1
"$@"Todos os argumentos, cada um separadoDe argv[1] até o fim
"$*"Todos os argumentos unidos em um só com espaços—

Um programa em Python recebe os mesmos argumentos como a lista sys.argv. Ao passar três argumentos com [python3 -c], o my file.txt entre aspas entrou em um único item da lista, e o primeiro item recebeu -c.

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

"$@" e "$*" dão resultados diferentes quando ficam entre aspas duplas. Para ver a diferença, criamos o star.sh, que mostra as duas formas uma depois da outra.

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

Executamos o star.sh com três argumentos: a, "b c" e d.

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

"$@" passou os três argumentos separados, enquanto "$*" os uniu com espaços e passou como um só.

Por isso, para repassar os argumentos recebidos a outro comando sem mudanças, use "$@".

shift descarta $1 e adianta os argumentos restantes uma posição. É usado em scripts que leem primeiro uma opção e tratam o resto como uma lista de arquivos.

Criamos o shift.sh, que mostra $1 e $# antes e depois do shift.

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

Executamos o shift.sh com três argumentos: -v, a.txt e b.txt.

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

A partir do décimo argumento, o número vai entre chaves, como em ${10}. Criamos o ten.sh, que mostra $10 e ${10} lado a lado.

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

Passamos 11 argumentos, de a até k, para o ten.sh.

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

$10 saiu como a0, ou seja, $1 seguido de um 0, enquanto ${10} saiu como o décimo argumento, j.

🔲 Simulador de argumentos de linha de comando

No simulador abaixo, você pode passar aspas, curingas e -- para o args.sh e também digitar comandos para ver como ls e getopt leem as opções e como star.sh e shift.sh recebem os argumentos.

Simulador de argumentos de linha de comandobash 5.1
[root@server work]#
É um servidor AlmaLinux virtual que funciona só no seu navegador; o args.sh mostra os argumentos recebidos com seus números, e ↑↓ traz de volta os comandos usados antes.

🔢 FAQ & conteúdo recomendado

O limite do tamanho somado de argumentos e variáveis de ambiente é conferido com [getconf ARG_MAX]; no servidor AlmaLinux 9.8 era de 2097152 bytes. Acima desse limite, o programa não é executado e aparece o erro [Argument list too long]. Quando há muitíssimos arquivos, não os passe todos de uma vez com um curinga; divida-os com o -exec do find ou com xargs.

Um argumento (argument) é o valor realmente passado ao executar um comando, e um parâmetro (parameter) é o nome que recebe esse valor do lado de quem recebe. Em um script shell, parâmetros posicionais como $1 e $2 recebem os argumentos passados.

O getopts, embutido no bash, lê uma por vez as opções curtas como -v. Ele não lê opções longas; para aceitar também opções longas como --verbose, organize antes os argumentos com o comando getopt usado acima.

ℹ️ Aviso de afiliados
O conteúdo deste site contém links de afiliados. Quando um visitante compra um produto ou serviço por meio de um desses links, o site recebe uma comissão do vendedor. O valor que o comprador paga (em promoções, ele diminui ↓) não aumenta por causa disso. Preços, descontos e informações de estoque valem para o momento em que o texto foi escrito e podem ter mudado, por isso confirme com o vendedor antes de comprar. Os produtos são escolhidos e avaliados por critérios próprios, e o recebimento de comissão não influencia a ordem de apresentação nem o conteúdo das avaliações.

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Demonstre sua humanidade: 9   +   9   =