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

Test ortamıRHEL ailesiAlmaLinux 9.8bash 5.1root hesabı
Kabuk$1$#--

Linux komut satırı argümanları (command-line argument), komut adının ardından boşluklarla ayrılarak yazılan ve programa aktarılan değerlerdir. Bir AlmaLinux 9 sunucusunda, aldığı argümanları olduğu gibi yazdıran bir test betiğine seçenekler, tırnaklar, joker karakterler ve -- verdik: argümanları ayıran kabuktu, seçenekleri okuyan ise her komutun kendisiydi.

Aşağıdaki çıktı, bir AlmaLinux 9.8 sunucusunun root hesabında bash 5.1 ile çalıştırılan sonucun aynısıdır. Test betikleri ve örnek dosyalar ayrı bir çalışma klasöründe oluşturuldu; /home/user/www yolu örnek bir değerdir.

1️⃣ Linux komut satırı argümanları nedir?

Komut satırına [komut arg1 arg2] gibi bir şey yazdığınızda kabuk sözcükleri boşluklardan ayırır. İlk sözcük çalıştırılacak program olur, kalan sözcükler ise sırayla o programa argüman olarak aktarılır.

Aktarılan argümanları görmek için çalışma klasöründe args.sh oluşturduk. $0 çalıştırıldığı adı, $# argüman sayısını, $1 ve sonrası ise argümanları sırayla tutar. Köşeli ayraçlar her argümanın nerede başlayıp bittiğini göstermek için eklendi.

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

Betiğe çalıştırma izni verdikten sonra onu üç sözcükle çalıştırdık: a, b ve c.

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

Üç sözcük $1, $2 ve $3'e girdi ve $# 3 oldu. Betiği adını bash'in ardına yazarak çalıştırırsanız $0, yazdığınız ad olan args.sh'yi aynen tutar.

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

Yalnızca $0, args.sh olarak değişti; üç argüman ve sayıları öncekiyle aynıydı.

2️⃣ Komut satırı argümanları ve komut seçenekleri

Linux komutları genellikle [komut -seçenek argüman] sırasıyla yazılır. Seçenekler komutun nasıl çalışacağını değiştirir, argümanlar ise komutun üzerinde çalışacağı dosyaları, yolları ya da değerleri belirler.

ls -l /home/user/www

Kabuk açısından -l de yalnızca bir argümandır. Aynı sözcükleri args.sh'ye verdiğimizde -l $1'e, yol ise $2'ye girdi.

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

-l'yi seçenek olarak okuyan ls'dir. Bu yüzden aynı harf her komutta farklı anlama gelir: head'deki -n yazdırılacak satır sayısını belirler, ls'deki -n ise sahipleri ad yerine numara olarak gösterir.

Bazı seçenekler hemen ardından gelen sözcüğü kendi değeri olarak alır. find komutunda -type f'yi, -name ise "*.txt"yi kendi değeri olarak kullanır; seçeneğe bu şekilde bağlı değere seçenek argümanı denir.

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

Bu komuttaki baştaki . hiçbir seçeneğe bağlı olmayan bir argümandır ve aramanın başlayacağı klasörü belirler.

3️⃣ Linux komut seçeneği biçimleri

Tek tireyle başlayan kısa seçenekler tek harftir ve birkaçı bitişik yazılabilir. Önce çalışma klasöründeki site klasörünü [ls -l -a] ile listeledik.

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

Ardından bunu, iki harfi bitişik yazan [ls -la] çıktısıyla diff kullanarak karşılaştırdık.

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

İki çıktı arasında tek bir karakter bile fark yoktu. İki tireyle başlayan uzun seçenekler sözcük olarak yazılır; ls'deki --all, -a ile aynı seçenek olduğundan [ls -l --all site] da aynı sonucu verdi.

Uzun seçenekler, yalnızca başı yazılsa bile tek bir seçeneğe karşılık geliyorsa kabul edilir. --al, --all ve --almost-all olmak üzere iki seçeneğe uyduğu için ls liste yazdırmadı ve 2 çıkış koduyla bitti.

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

Değer alan seçenekler birkaç biçimde yazılabilir. head ile a.txt'nin ilk iki satırını yazdırırken kısa seçenek değeri bitişik alarak [-n2] şeklinde yazılabilir.

head -n2 a.txt
alpha
beta

Uzun seçenek değeri eşittir işaretiyle bağlar: [--lines=2].

head --lines=2 a.txt
alpha
beta

Boşlukla ayrılmış [-n 2] ve [--lines 2] dahil dört biçimin hepsi alpha ve beta olmak üzere iki satırı yazdırdı.

ls, head ve cat seçeneklerini C kütüphanesinin getopt_long işleviyle okur. Üç program dosyasına strings ile bakınca hepsinde bu işlev adının bulunduğu görüldü.

Aynı kuralları kabukta denetlemek için util-linux'taki getopt komutu kullanılır. -o'nun ardına kısa seçenekler, -l'nin ardına uzun seçenekler yazılır; bir harfin ardındaki iki nokta, o seçeneğin değer aldığı anlamına gelir.

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

Bitişik yazılan -la, -l ve -a olarak ayrıldı; -n 2 ise -n ve 2 değeri olarak birleştirildi. Seçenek olmayan a.txt en sona, -- işaretinin ardına taşındı.

4️⃣ Tırnak içindeki argümanlar ve joker karakterler

Boşluk içeren bir dosya adı, tek bir argüman olarak aktarılması için tırnak içine alınmalıdır.

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

Tırnaksız yazınca my ile file.txt ayrı ayrı bölündü ve $# 3 oldu. Bunu ls veya cat'e böyle verirseniz my ve file.txt adlı iki dosyayı arar.

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

Joker karakterleri, program almadan önce kabuk dosya adlarına çevirir. Çalışma klasöründe *.txt verdiğimizde .txt ile biten dört dosya ad sırasıyla geldi.

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

Tırnak içindeki "*.txt" kabuk tarafından değiştirilmedi ve harfi harfine tek bir argüman oldu. find'ın -name seçeneği gibi deseni programın kendisinin karşılaştırdığı seçeneklerde, değer bu şekilde tırnak içinde verilir.

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

Boş tırnaklar da tek bir boş argüman olarak aktarılır. [./args.sh '' b] çalıştırıldığında $# 2 oldu ve $1 boştu.

5️⃣ Komut seçeneklerinin sonu (--)

Adı -n olan bir dosya gibi tireyle başlayan argümanları komut seçenek olarak okur. Yalnızca o dosyanın bulunduğu dash klasöründe [ls -n] çalıştırdığımızda ls, -n'yi dosya adı olarak değil sayısal çıktı seçeneği olarak aldı ve klasörü listeledi.

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

-- işaretinin ardına yazılan argümanlar tireyle başlasa bile seçenek olarak okunmaz. [ls -- -n] yalnızca -n adlı dosyayı yazdırdı.

ls -- -n
-n

Tek bir komutun içinde de aynı karakterler -- öncesinde ve sonrasında farklı okunur. cat'e -n'yi iki kez verdiğimizde öndeki -n satır numarası seçeneği, -- sonrasındaki -n ise dosya adı olarak okundu ve dosya içeriği satır numaralarıyla çıktı.

cat -n -- -n
     1	dash file

Başına yol ekleyip ./-n yazmak da bir yöntemdir; bu durumda argüman tireyle başlamadığı için aynı -n dosyası olarak okunur.

-- işaretini seçeneklerin sonu olarak okumak da komut tarafının bir kuralıdır. Seçenek okumayan args.sh'ye verdiğimizde -- da olduğu gibi $1'e girdi.

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

POSIX yardımcı program kuralları, seçenek argümanı olmayan ilk -- işaretinin seçeneklerin sonu olarak kabul edilmesini öngörür. Bu nedenle bu kurallara uyan komutlarda - ile başlayan dosya adları -- işaretinin ardına yazılır.

6️⃣ Kabuk betiğinde komut satırı argümanlarını almak

Kabuk betiği aldığı argümanları konumsal parametreler ve özel parametrelerle okur. Bir C programının main(int argc, char *argv[]) işlevi de aynı argümanları aldığından, ikisi yan yana konunca aşağıdaki gibi görünür.

Parametreİçerdiği değerC dilinde main işlevi
$0Çalıştırılan betiğin adıargv[0]
$1 ~ $9Birinciden dokuzuncuya kadar argümanlarargv[1] ~ argv[9]
${10}Onuncu argümandan itibaren süslü parantez içindeargv[10]
$#Argüman sayısı, $0 sayılmazargc - 1
"$@"Tüm argümanlar, her biri ayrıargv[1]'den sonuna kadar
"$*"Tüm argümanlar boşlukla birleştirilmiş tek bir değer—

Bir Python programı aynı argümanları sys.argv listesi olarak alır. [python3 -c] ile üç argüman verdiğimizde tırnak içindeki my file.txt listenin tek bir öğesine girdi, ilk öğede ise -c vardı.

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

"$@" ve "$*" çift tırnak içine alındığında farklı sonuç verir. Bu farkı görmek için iki biçimi art arda yazdıran star.sh'yi oluşturduk.

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

star.sh'yi üç argümanla çalıştırdık: a, "b c" ve d.

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

"$@" üç argümanı ayrı ayrı aktardı, "$*" ise onları boşlukla birleştirip tek bir argüman olarak aktardı.

Bu yüzden alınan argümanları başka bir komuta olduğu gibi aktarırken "$@" kullanılır.

shift, $1'i atar ve kalan argümanları birer konum öne kaydırır. Önce bir seçeneği okuyup gerisini dosya listesi olarak işleyen betiklerde kullanılır.

shift öncesinde ve sonrasında $1 ile $# değerini yazdıran shift.sh'yi oluşturduk.

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

shift.sh'yi üç argümanla çalıştırdık: -v, a.txt ve b.txt.

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

Onuncu argümandan itibaren sayı ${10} gibi süslü parantez içine alınır. $10 ile ${10} değerini yan yana yazdıran ten.sh'yi oluşturduk.

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

ten.sh'ye a'dan k'ye kadar 11 argüman verdik.

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

$10, $1'in ardına 0 eklenmiş a0 olarak, ${10} ise onuncu argüman j olarak çıktı.

🔲 Komut satırı argümanı simülatörü

Aşağıdaki simülatörde args.sh'ye tırnak, joker karakter ve -- vererek deneyebilir, ls ile getopt'un seçenekleri nasıl okuduğunu, star.sh ile shift.sh'nin argümanları nasıl aldığını da komutları kendiniz yazarak görebilirsiniz.

Komut satırı argümanı simülatörübash 5.1
[root@server work]#
Yalnızca tarayıcınızda çalışan sanal bir AlmaLinux sunucusudur; args.sh aldığı argümanları numaralarıyla birlikte yazdırır, ↑↓ ise daha önce kullandığınız komutları geri getirir.

🔢 SSS & önerilen içerikler

Argümanlarla ortam değişkenlerinin toplam uzunluğunun üst sınırı [getconf ARG_MAX] ile denetlenir; AlmaLinux 9.8 sunucusunda bu değer 2097152 bayttı. Bu sınır aşılırsa program çalışmaz ve [Argument list too long] hatası çıkar. Dosya sayısı çok fazla olduğunda bunları joker karakterle bir kerede vermek yerine find'ın -exec seçeneği veya xargs ile bölerek verin.

Argüman (argument), bir komutu çalıştırırken gerçekten verilen değerdir; parametre (parameter) ise o değeri alan tarafın kullandığı addır. Kabuk betiğinde $1, $2 gibi konumsal parametreler aktarılan argümanları alır.

bash'te yerleşik olan getopts, -v gibi kısa seçenekleri tek tek okur. Uzun seçenekleri okumadığından --verbose gibi uzun seçenekleri de almak istediğinizde argümanları önce yukarıda kullanılan getopt komutuyla düzenleyin.

ℹ️ Satış ortaklığı bildirimi
Bu sitenin içeriklerinde satış ortaklığı bağlantıları bulunur. Bir ziyaretçi bu bağlantılar üzerinden ürün veya hizmet satın alırsa bu site satıcıdan komisyon alır. Bu süreçte alıcının ödediği tutar (kampanya indirimlerinde tutar düşer↓) artmaz. Yayımlanan fiyat, indirim ve stok bilgileri yazının yazıldığı zamana aittir ve gerçek durumdan farklı olabilir; bu yüzden satın almadan önce son bilgiyi satıcıdan kontrol etmenizi rica ederiz. Ürünler kendi ölçütlerimize göre seçilir ve değerlendirilir; komisyon alınıp alınmaması tanıtım sırasını veya değerlendirme içeriğini etkilemez.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

İnsan olduğunuzu kanıtlayın: 7   +   7   =