리눅스 명령행 인자: 명령어 옵션과 따옴표, 옵션 끝 표시, $1, $# 받기
Argumenty wiersza poleceń w Linuksie (command-line argument) to wartości przekazywane programowi przez wpisanie ich po nazwie polecenia, oddzielonych spacjami. Gdy na serwerze AlmaLinux 9 przekazaliśmy opcje, cudzysłowy, symbole wieloznaczne i -- do skryptu testowego, który wypisuje otrzymane argumenty bez zmian, okazało się, że argumenty dzieli powłoka, a opcje odczytuje każde polecenie samo.
Poniższe wyniki to dokładnie to, co otrzymano w bash 5.1 na koncie root serwera AlmaLinux 9.8. Skrypty testowe i przykładowe pliki utworzono w osobnym folderze roboczym, a ścieżka /home/user/www to wartość przykładowa.
1️⃣ Czym są argumenty wiersza poleceń w Linuksie?
Gdy w wierszu poleceń wpiszesz coś w rodzaju [polecenie arg1 arg2], powłoka podzieli tekst na słowa w miejscach spacji. Pierwsze słowo staje się programem do uruchomienia, a pozostałe trafiają po kolei do tego programu jako jego argumenty.
Aby zobaczyć przekazane argumenty, utworzyliśmy w folderze roboczym args.sh. $0 zawiera nazwę, pod którą go uruchomiono, $# liczbę argumentów, a od $1 kolejne argumenty. Nawiasy kwadratowe dodano, by było widać, gdzie każdy argument się zaczyna i kończy.
#!/bin/bash
echo "\$0 = $0"
echo "\$# = $#"
i=1
for a in "$@"; do
echo "\$$i = [$a]"
i=$((i+1))
doneNadaliśmy skryptowi prawo wykonywania i uruchomiliśmy go z trzema słowami: a, b i c.
./args.sh a b c$0 = ./args.sh
$# = 3
$1 = [a]
$2 = [b]
$3 = [c]Trzy słowa trafiły do $1, $2 i $3, a $# wyniosło 3. Jeśli uruchomisz skrypt, wpisując jego nazwę po bash, $0 zawiera nazwę dokładnie tak, jak ją wpisano, czyli args.sh.
bash args.sh a b c$0 = args.sh
$# = 3
$1 = [a]
$2 = [b]
$3 = [c]Zmieniło się tylko $0 na args.sh; trzy argumenty i ich liczba były takie same jak wcześniej.
2️⃣ Argumenty wiersza poleceń a opcje poleceń
Polecenia Linuksa zapisuje się zwykle w kolejności [polecenie -opcja argument]. Opcje zmieniają sposób działania polecenia, a argumenty wskazują pliki, ścieżki lub wartości, na których ono pracuje.
ls -l /home/user/wwwDla powłoki -l to też tylko argument. Po przekazaniu tych samych słów do args.sh -l trafiło do $1, a ścieżka do $2.
./args.sh -l /home/user/www$0 = ./args.sh
$# = 2
$1 = [-l]
$2 = [/home/user/www]Odczytanie -l jako opcji to zadanie ls. Dlatego ta sama litera znaczy co innego w różnych poleceniach: -n w head ustala liczbę wypisywanych wierszy, a -n w ls pokazuje właściciela jako numer zamiast nazwy.
Niektóre opcje biorą jako swoją wartość słowo stojące tuż za nimi. W poleceniu find -type bierze f, a -name bierze "*.txt" jako wartość; taka wartość przypisana do opcji to argument opcji.
find . -type f -name "*.txt"Kropka . na początku tego polecenia to argument niezwiązany z żadną opcją, który wskazuje folder, od którego zaczyna się wyszukiwanie.
3️⃣ Formy zapisu opcji poleceń w Linuksie
Krótkie opcje zaczynają się od jednego myślnika, mają jedną literę i można je zapisywać razem. Najpierw wypisaliśmy folder site z folderu roboczego poleceniem [ls -l -a].
ls -l -a sitetotal 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.htmlNastępnie porównaliśmy to za pomocą diff z wynikiem [ls -la], w którym obie litery są zapisane razem.
diff <(ls -l -a site) <(ls -la site) && echo samesameOba wyniki nie różniły się ani jednym znakiem. Długie opcje zaczynają się od dwóch myślników i zapisuje się je jako słowa; --all w ls to ta sama opcja co -a, więc [ls -l --all site] też dało ten sam wynik.
Długie opcje są przyjmowane, nawet gdy wpiszesz tylko ich początek, o ile pasuje on do jednej opcji. --al pasowało do dwóch opcji, --all i --almost-all, więc ls nie wypisało listy i zakończyło się kodem wyjścia 2.
ls --al sitels: option '--al' is ambiguous; possibilities: '--all' '--almost-all'
Try 'ls --help' for more information.Opcje przyjmujące wartość można zapisać na kilka sposobów. Przy wypisywaniu dwóch pierwszych wierszy pliku a.txt poleceniem head krótka opcja może mieć wartość dopisaną bez spacji, jak [-n2].
head -n2 a.txtalpha
betaDługa opcja łączy wartość znakiem równości, jak [--lines=2].
head --lines=2 a.txtalpha
betaWszystkie cztery formy, także [-n 2] i [--lines 2] ze spacją, wypisały dwa wiersze alpha i beta.
ls, head i cat odczytują opcje funkcją getopt_long z biblioteki C. Przegląd trzech plików programów poleceniem strings pokazał, że każdy zawiera nazwę tej funkcji.
Aby sprawdzić te same reguły w powłoce, używa się polecenia getopt z util-linux. Po -o wpisuje się krótkie opcje, a po -l długie; dwukropek po literze oznacza, że opcja przyjmuje wartość.
getopt -o lan: -l all,lines: -- -la -n 2 --all a.txt -l -a -n '2' --all -- 'a.txt'Zapisane razem -la zostało rozdzielone na -l i -a, a -n 2 połączone w -n z wartością 2. a.txt, które nie jest opcją, przeniesiono na koniec, za --.
4️⃣ Argumenty w cudzysłowie i symbole wieloznaczne
Nazwę pliku ze spacją trzeba ująć w cudzysłów, aby przeszła jako jeden argument.
./args.sh "my file.txt" report.txt$0 = ./args.sh
$# = 2
$1 = [my file.txt]
$2 = [report.txt]Bez cudzysłowu my i file.txt zostały rozdzielone, a $# wyniosło 3. Jeśli przekażesz to tak do ls lub cat, będą szukać dwóch plików o nazwach my i file.txt.
./args.sh my file.txt report.txt$0 = ./args.sh
$# = 3
$1 = [my]
$2 = [file.txt]
$3 = [report.txt]Symbole wieloznaczne powłoka zamienia na nazwy plików, zanim program je otrzyma. Po przekazaniu *.txt w folderze roboczym trafiły tam w kolejności alfabetycznej cztery pliki kończące się na .txt.
./args.sh *.txt$0 = ./args.sh
$# = 4
$1 = [a.txt]
$2 = [b.txt]
$3 = [my file.txt]
$4 = [report.txt]Ujęte w cudzysłów "*.txt" nie zostało zamienione przez powłokę i stało się jednym argumentem, znak w znak. Przy opcjach takich jak -name w find, gdzie program sam porównuje wzorzec, przekazuje się go właśnie tak, w cudzysłowie.
./args.sh "*.txt"$0 = ./args.sh
$# = 1
$1 = [*.txt]Pusty cudzysłów też przechodzi jako jeden pusty argument. Po uruchomieniu [./args.sh '' b] $# wyniosło 2, a $1 było puste.
5️⃣ Koniec opcji polecenia (--)
Argument zaczynający się od myślnika, na przykład plik o nazwie -n, polecenie odczytuje jako opcję. Po uruchomieniu [ls -n] w folderze dash, w którym jest tylko ten plik, ls potraktowało -n nie jako nazwę pliku, lecz jako opcję wyjścia numerycznego, i wypisało zawartość folderu.
ls -ntotal 4
-rw-r--r-- 1 0 0 10 Oct 28 16:00 -nArgumenty wpisane po -- nie są odczytywane jako opcje, nawet jeśli zaczynają się od myślnika. [ls -- -n] wypisało tylko nazwę pliku -n.
ls -- -n-nW jednym poleceniu te same znaki są odczytywane inaczej przed -- i po nim. Gdy przekazaliśmy -n do cat dwa razy, pierwsze -n zostało odczytane jako opcja numerów wierszy, a -n po -- jako nazwa pliku, więc zawartość pliku pojawiła się z numerami wierszy.
cat -n -- -n 1 dash fileMożna też dodać ścieżkę i zapisać ./-n; wtedy argument nie zaczyna się od myślnika i jest odczytywany jako ten sam plik -n.
Traktowanie -- jako końca opcji to także reguła po stronie polecenia. Po przekazaniu do args.sh, który nie odczytuje opcji, -- też trafiło bez zmian do $1.
./args.sh -- -a$0 = ./args.sh
$# = 2
$1 = [--]
$2 = [-a]Konwencje narzędzi POSIX stanowią, że pierwsze --, które nie jest argumentem opcji, przyjmuje się jako koniec opcji. Dlatego w poleceniach zgodnych z tymi konwencjami nazwy plików zaczynające się od - wpisuje się po --.
6️⃣ Odbieranie argumentów wiersza poleceń w skrypcie powłoki
Skrypt powłoki odczytuje otrzymane argumenty przez parametry pozycyjne i parametry specjalne. main(int argc, char *argv[]) w programie w C otrzymuje te same argumenty, więc zestawione obok siebie wyglądają tak.
| Parametr | Zawarta wartość | Funkcja main w C |
|---|---|---|
| $0 | Nazwa uruchomionego skryptu | argv[0] |
| $1 ~ $9 | Argumenty od pierwszego do dziewiątego | argv[1] ~ argv[9] |
| ${10} | Od dziesiątego argumentu w nawiasach klamrowych | argv[10] |
| $# | Liczba argumentów, bez $0 | argc - 1 |
| "$@" | Wszystkie argumenty, każdy osobno | Od argv[1] do końca |
| "$*" | Wszystkie argumenty złączone spacjami w jeden | — |
Program w Pythonie otrzymuje te same argumenty jako listę sys.argv. Po przekazaniu trzech argumentów przez [python3 -c] ujęte w cudzysłów my file.txt trafiło do jednego elementu listy, a w pierwszym elemencie znalazło się -c.
python3 -c 'import sys; print(sys.argv)' a "my file.txt" -l['-c', 'a', 'my file.txt', '-l']"$@" i "$*" dają różne wyniki, gdy są ujęte w podwójny cudzysłów. Aby zobaczyć różnicę, utworzyliśmy star.sh, który wypisuje obie formy po kolei.
#!/bin/bash
echo 'with "$@"'
printf ' [%s]\n' "$@"
echo 'with "$*"'
printf ' [%s]\n' "$*"Uruchomiliśmy star.sh z trzema argumentami: a, "b c" i d.
./star.sh a "b c" dwith "$@"
[a]
[b c]
[d]
with "$*"
[a b c d]"$@" przekazało trzy argumenty osobno, a "$*" połączyło je spacjami i przekazało jako jeden.
Dlatego gdy przekazujesz otrzymane argumenty bez zmian do innego polecenia, używaj "$@".
shift odrzuca $1 i przesuwa pozostałe argumenty o jedną pozycję do przodu. Stosuje się go w skryptach, które najpierw odczytują jedną opcję, a resztę traktują jako listę plików.
Utworzyliśmy shift.sh, który wypisuje $1 i $# przed shift i po nim.
#!/bin/bash
echo "before shift: \$1 = $1, \$# = $#"
shift
echo "after shift: \$1 = $1, \$# = $#"Uruchomiliśmy shift.sh z trzema argumentami: -v, a.txt i b.txt.
./shift.sh -v a.txt b.txtbefore shift: $1 = -v, $# = 3
after shift: $1 = a.txt, $# = 2Od dziesiątego argumentu liczbę ujmuje się w nawiasy klamrowe, jak ${10}. Utworzyliśmy ten.sh, który wypisuje obok siebie $10 i ${10}.
#!/bin/bash
echo "\$10 = $10"
echo "\${10} = ${10}"Do ten.sh przekazaliśmy 11 argumentów, od a do k.
./ten.sh a b c d e f g h i j k$10 = a0
${10} = j$10 dało a0, czyli $1 z dopisanym 0, a ${10} dało dziesiąty argument, j.
🔲 Symulator argumentów wiersza poleceń
W symulatorze poniżej możesz przekazywać do args.sh cudzysłowy, symbole wieloznaczne i --, a także samodzielnie wpisywać polecenia, by zobaczyć, jak ls i getopt odczytują opcje oraz jak star.sh i shift.sh odbierają argumenty.
🔢 FAQ & polecane treści
Symbole wieloznaczne
[Znaki specjalne powłoki] Symbole wieloznaczne w Linuksie (metaznaki)
Artykuł, który na przykładach pokazuje, jak wybierać nazwy plików symbolami wieloznacznymi, takimi jak * i ?, oraz klasami znaków.
Wiele poleceń
[Linux] 5 sposobów łączenia poleceń (średnik, potok, ampersand..)
Artykuł o pięciu sposobach uruchamiania wielu poleceń w jednym wierszu za pomocą średnika, potoku, &&, || i &.
Wypisywanie tekstu
Polecenie echo: From rozwijanie i cytowanie
Artykuł o tym, jak wypisywać tekst i wartości zmiennych poleceniem echo, oraz o jego opcjach.
ℹ️ Informacja o linkach partnerskich
Treści tej witryny zawierają linki partnerskie. Jeśli odwiedzający kupi produkt lub usługę przez taki link, witryna otrzymuje od sprzedawcy prowizję. Kwota płacona przy tym przez kupującego (podczas promocji spada↓) nie wzrasta. Podane ceny, rabaty i dostępność odnoszą się do chwili pisania i mogą różnić się od stanu faktycznego, dlatego przed zakupem sprawdź je u sprzedawcy. Produkty wybieramy i oceniamy według własnych kryteriów, a prowizja nie wpływa ani na kolejność prezentacji, ani na treść ocen.