Bash komut geçmişi, etkileşimli kabukta yazdığınız komutların numaralı bir listesidir. history komutu bu listeyi gösterir, !! son komutu, !$ son komutun son argümanını, !n ise n numaralı komutu yeniden kullanır. Liste kabuk açılırken HISTFILE dosyasından (varsayılan ~/.bash_history) okunur, kabuk kapanırken o dosyaya yazılır. Kaç komutun tutulacağını HISTSIZE ve HISTFILESIZE, hangi komutların kaydedilmeyeceğini HISTCONTROL ve HISTIGNORE, zaman damgasını ise HISTTIMEFORMAT belirler.
Bu yazıda geçmiş listesi ile geçmiş dosyasının nasıl çalıştığını, ilgili değişkenleri, history ve fc komutlarının seçeneklerini, ! ile başlayan geçmiş genişletmesinin olay, kelime ve değiştirici sözdizimini ve birden çok terminalde geçmişin kaybolmasını önlemeyi göreceksiniz. Geçmiş etkileşimli kabuğun özelliğidir, ama örnekleri tekrarlanabilir kılmak için betik içinde set -o history ve set -H ile açıp çalıştırdık. Kaynak, GNU Bash Reference Manual'ın 9. bölümü (Using History Interactively) ve değişken açıklamalarıdır.
Geçmiş listesi ve geçmiş dosyası

İki ayrı şeyi ayırt etmek gerekir. Geçmiş listesi kabuğun belleğindedir; history komutu onu gösterir ve yukarı ok tuşu onda gezinir. Geçmiş dosyası ise diskteki kalıcı kopyadır. Kabuk açılırken liste dosyadan doldurulur; dosya gerekiyorsa HISTFILESIZE değerine göre kırpılır. Kabuk kapanırken listedeki son $HISTSIZE komut dosyaya kopyalanır. histappend kabuk seçeneği açıksa bu kopyalama dosyanın sonuna ekleme şeklinde yapılır; kapalıysa dosya baştan yazılır.
Kılavuzun önemli bir ayrıntısı: komutlar listeye parametre ve değişken genişletmesinden önce, ama geçmiş genişletmesinden sonra kaydedilir. Yani echo $HOME yazdığınızda listede echo $HOME durur, dizinin değeri değil; !! yazdığınızda ise listede !! değil, onun yerine geçen gerçek komut durur. HISTFILE ayarlı değilse ya da boşsa, veya dosya yazılamıyorsa, geçmiş kaydedilmez. Bu, bir oturumun geçmişini bilerek diske yazdırmamanın da bir yoludur: unset HISTFILE.
| Değişken veya seçenek | Görevi | Varsayılan |
|---|---|---|
| HISTFILE | geçmiş dosyasının adı | ~/.bash_history |
| HISTSIZE | listede tutulacak en fazla komut | 500 |
| HISTFILESIZE | dosyada tutulacak en fazla satır | HISTSIZE değeri |
| HISTCONTROL | boşlukla başlayan ve yinelenen satırları ayıklama | ayarlı değil |
| HISTIGNORE | kaydedilmeyecek satırların desen listesi | ayarlı değil |
| HISTTIMEFORMAT | zaman damgası biçimi (strftime) | ayarlı değil |
| shopt histappend | çıkışta dosyanın üzerine yazmak yerine ekleme | kapalı |
| shopt cmdhist ve lithist | çok satırlı komutu tek kayıtta tutma | cmdhist açık, lithist kapalı |
HISTSIZE için 0 değeri hiç komut kaydetmemek, sıfırdan küçük bir değer sınırsız kayıt anlamına gelir. HISTFILESIZE için 0 dosyayı sıfır boyuta indirir; sayısal olmayan ya da negatif bir değer ise kırpmayı tamamen kapatır. Her iki varsayılan da kabuk başlangıç dosyalarını okuduktan sonra atanır; bu yüzden kendi değerlerinizi ~/.bashrc içine yazmanız yeterlidir. Hangi dosyanın ne zaman okunduğu .bashrc ve .bash_profile farkı yazısında.
Aşağıdaki örnek HISTSIZE=3 ile listenin nasıl kırpıldığını ve history -w ile dosyaya ne yazıldığını gösteriyor. Betik içinde geçmişi set -o history ile açtığımız için betiğin kendi satırları da, yorum satırları dahil, tıpkı etkileşimli kabukta yazılmış gibi listeye giriyor; bu yüzden bu yazıdaki geçmiş örneklerinde çıktıları kodun sonunda topluca gösteriyoruz. Geçmiş açıldığı anda HISTFILE ayarlıysa dosya listeye okunur; örneğin her çalıştırmada aynı sonucu vermesi için HISTFILE değerini geçmişi açtıktan sonra veriyoruz:
HISTSIZE=3
set -o history
HISTFILE=./gecmis.txt
echo a >/dev/null
echo b >/dev/null
echo c >/dev/null
history
history -w
cat ./gecmis.txt
# çıktı (history):
# 3 echo b >/dev/null
# 4 echo c >/dev/null
# 5 history
# çıktı (cat ./gecmis.txt):
# echo c >/dev/null
# history
# history -wNumaralar küçülmedi: liste en fazla üç kayıt tutuyor, ama her komut kendi geçmiş numarasını koruyor. Dosyaya yazılırken numaralar kaydedilmez, yalnızca komut metni yazılır.
HISTCONTROL ve HISTIGNORE: neyin kaydedileceğini seçmek
HISTCONTROL iki nokta ile ayrılmış bir değer listesidir. ignorespace boşlukla başlayan satırları, ignoredups bir önceki kayıtla aynı olan satırları kaydetmez; ignoreboth ikisinin kısaltmasıdır. erasedups ise yeni satırı kaydetmeden önce listedeki bütün eşlerini siler, böylece her komut listede yalnızca bir kez, en son kullanıldığı yerde görünür. Listede tanınmayan değerler yok sayılır.
HISTIGNORE yine iki nokta ile ayrılmış, ama bu kez desenlerden oluşan bir listedir. Kılavuzun altını çizdiği kural şudur: her desen satırın başına sabitlenir ve satırın tamamıyla eşleşmelidir; Bash sona kendiliğinden * eklemez. Desenlerde kabuğun normal joker karakterlerinin yanında & bir önceki geçmiş satırı anlamına gelir. Bu kuralı aşağıdaki örnekte pwd deseniyle görüyorsunuz:
HISTCONTROL=ignoreboth
HISTIGNORE='pwd:history*'
set -o history
echo bir
echo bir
echo gizli
pwd >/dev/null
echo iki
history
# çıktı:
# bir
# bir
# gizli
# iki
# 1 echo bir
# 2 pwd >/dev/null
# 3 echo ikiİkinci echo bir yinelendiği için, boşlukla başlayan echo gizli de ignorespace yüzünden kaydedilmedi. history satırı history* desenine uydu. Ama pwd >/dev/null kaydedildi: pwd deseni satırın tamamıyla eşleşmiyor. Yalnızca pwd ile başlayan her satırı dışlamak isteseydik deseni pwd* yazmalıydık. Desen sözdiziminin tamamı joker karakterler ve glob yazısında; extglob açıksa genişletilmiş desenler de kullanılabilir.
Çok satırlı bileşik komutlarda bir ayrıntı daha vardır: komutun ilk satırı kaydedildiyse sonraki satırlar HISTCONTROL ve HISTIGNORE denetimine girmeden kaydedilir; ilk satır kaydedilmediyse diğerleri de kaydedilmez. cmdhist açıkken bütün satırlar tek bir kayıtta, gerekli yerlere noktalı virgül eklenerek tutulur; lithist de açıksa noktalı virgül yerine gerçek satır sonları korunur.
HISTTIMEFORMAT ile zaman damgası
HISTTIMEFORMAT ayarlı ve boş değilse history her kaydın önüne, bu değeri strftime biçimi olarak kullanıp zamanı yazar; aradaki boşluğu biçimin içine kendiniz koymalısınız. Değişken ayarlıysa Bash zaman damgalarını geçmiş dosyasına da yazar: her kaydın üstünde geçmiş yorum karakteriyle (varsayılan #) başlayan ve hemen bir rakamla devam eden bir satır olur. Dosya okunurken bu satırlar zaman damgası olarak yorumlanır ve aynı zamanda çok satırlı kayıtların sınırını belirler. Örnekte saatler her çalıştırmada değişeceği için zaman damgası satırlarını sed ile maskeledik:
HISTTIMEFORMAT='%F %T '
set -o history
HISTFILE=./zaman.txt
echo merhaba >/dev/null
history -w
sed 's/^#[0-9]*$/#<zaman damgası>/' ./zaman.txt
# çıktı:
# #<zaman damgası>
# HISTFILE=./zaman.txt
# #<zaman damgası>
# echo merhaba >/dev/null
# #<zaman damgası>
# history -whistory çıktısında ise her satır 1 2026-11-07 14:03:12 echo merhaba biçiminde görünür; %F tarihi yıl-ay-gün, %T saati saat:dakika:saniye olarak verir.
history komutunun seçenekleri

| Komut | Etkisi |
|---|---|
| history | listeyi numaralarıyla gösterir; * ile işaretli kayıtlar değiştirilmiştir |
| history 20 | yalnızca son 20 kaydı gösterir |
| history -c | listeyi tamamen temizler |
| history -d 15 | 15 numaralı kaydı siler; negatif sayı sondan sayar |
| history -d 10-20 | 10 ile 20 arasındaki kayıtları (dahil) siler |
| history -a | bu oturumda eklenen ve henüz dosyaya yazılmamış satırları dosyaya ekler |
| history -n | dosyaya bu oturum başladıktan sonra eklenen satırları listeye okur |
| history -r | dosyanın tamamını okuyup listenin sonuna ekler |
| history -w | listenin tamamını dosyanın üzerine yazar |
| history -p arg | arg üzerinde geçmiş genişletmesi yapıp sonucu yazar, listeye kaydetmez |
| history -s arg | arg değerini çalıştırmadan listeye tek kayıt olarak ekler |
-w, -r, -a ve -n seçeneklerine bir dosya adı verirseniz HISTFILE yerine o dosya kullanılır. -d için negatif konum, son kaydın bir fazlasına göre hesaplanır; history -d -1 o anki history -d komutunun kendisini gösterir. Geçmiş numarasını kabuk içinden HISTCMD değişkeniyle okuyabilirsiniz; atama yapmak etkisizdir. İstemde aynı numarayı \! kaçışı gösterir, bkz. PS1 prompt özelleştirme.
set -o history
echo bir >/dev/null
echo iki >/dev/null
echo "HISTCMD: $HISTCMD"
history -d 1
history
# çıktı:
# HISTCMD: 3
# 1 echo iki >/dev/null
# 2 echo "HISTCMD: $HISTCMD"
# 3 history -d 1
# 4 historyBir kayıt silindiğinde sonraki kayıtların numarası bir kaydı; !n ile numaraya başvuran bir alışkanlığınız varsa bunu hesaba katın.
Birden çok terminalde geçmiş neden kayboluyor?
Varsayılan davranışta her kabuk çıkarken kendi listesini dosyanın üzerine yazar. İki terminal açıp ikisinde de komut yazdığınızda, en son kapanan terminal diğerinin yazdıklarını silmiş olur. Çözüm iki parçalıdır: shopt -s histappend ile çıkışta ekleme yapılmasını sağlamak ve isterseniz history -a komutunu PROMPT_COMMAND içine koyarak her istemden önce yeni satırları dosyaya eklemek:
# ~/.bashrc
shopt -s histappend
HISTCONTROL=ignoreboth
HISTSIZE=5000
HISTFILESIZE=10000
HISTTIMEFORMAT='%F %T '
PROMPT_COMMAND+=('history -a')Bu düzenle her terminal yazdığı komutları hemen dosyaya ekler, ama diğer terminallerin eklediklerini kendi listesine kendiliğinden almaz; onları görmek istediğinizde history -n çalıştırabilirsiniz. PROMPT_COMMAND dizisinin nasıl çalıştığı PS1 prompt özelleştirme yazısında, shopt ise shopt seçenekleri yazısında.
Geçmiş genişletmesi: !! , !$ ve arkadaşları
Geçmiş genişletmesi, csh kabuğundan gelen ve ! karakteriyle başlayan bir kısaltma dilidir. Etkileşimli kabukta varsayılan olarak açıktır ve set +H ile kapatılır; etkileşimsiz kabukta kapalıdır, set -H ile açılır. Genişletme bir satır tamamen okunduktan hemen sonra, kabuk satırı kelimelere bölmeden önce yapılır. Bir ifadenin üç parçası vardır: hangi kaydın kullanılacağını seçen olay belirteci, o kayıttan hangi kelimelerin alınacağını seçen kelime belirteci ve seçilen kelimeleri düzenleyen değiştiriciler.
| İfade | Anlamı |
|---|---|
| !! | bir önceki komut (!-1 ile aynı) |
| !n | n numaralı kayıt |
| !-n | n kayıt öncesi |
| !metin | metin ile başlayan en son komut |
| !?metin? | içinde metin geçen en son komut |
| ^eski^yeni^ | son komutu eski yerine yeni koyarak tekrarla |
| !# | şu ana kadar yazılmış satırın tamamı |
| :0, :n, :^, :$ | sıfırıncı kelime (komut), n. kelime, ilk argüman, son kelime |
| :x-y, :*, :x* | kelime aralığı, sıfırıncı hariç tüm kelimeler, x ten sona |
| :h, :t | yolun son bileşenini at (baş), yalnızca son bileşeni bırak (kuyruk) |
| :r, :e | .uzantı kısmını at, yalnızca uzantıyı bırak |
| :s/eski/yeni/, :gs/eski/yeni/ | ilk eşleşmeyi, ya da g ile tümünü değiştir |
| :p | sonucu yazdır ama çalıştırma |
Kelime belirteci ^, $, *, - ya da % ile başlıyorsa aradaki iki nokta yazılmayabilir; !$ bu yüzden !!:$ ile aynıdır. Olay belirtilmeden yalnızca kelime belirteci yazılırsa bir önceki komut kullanılır. Aşağıdaki betik geçmişi ve genişletmeyi açıyor; kabuk her genişletilmiş satırı çalıştırmadan önce standart hataya yazıyor; bu satırları çıktıdan ayrı olarak gösterdik:
goster() { printf '%s\n' "$@"; }
set -o history -o histexpand
goster /etc/nginx/nginx.conf yedek/nginx.conf.bak
echo !$
echo !goster:1:h !goster:1:t !goster:2:r !goster:2:e
^nginx^apache
!goster:gs/nginx/apache/
# standart hataya yazılan genişletilmiş satırlar:
# echo yedek/nginx.conf.bak
# echo /etc/nginx nginx.conf yedek/nginx.conf .bak
# echo /etc/apache nginx.conf yedek/nginx.conf .bak
# goster /etc/apache/apache.conf yedek/apache.conf.bak
# çıktı:
# /etc/nginx/nginx.conf
# yedek/nginx.conf.bak
# yedek/nginx.conf.bak
# /etc/nginx nginx.conf yedek/nginx.conf .bak
# /etc/apache nginx.conf yedek/nginx.conf .bak
# /etc/apache/apache.conf
# yedek/apache.conf.bakKayıt kelimelere kabuğun girdiyi okurken kullandığı kurallarla bölünür; tırnak içindeki birkaç kelime tek kelime sayılır. Örnekteki goster, argümanlarını alt alta yazan küçük bir fonksiyon; onun satırında 0 numaralı kelime goster, 1 ve 2 numaralı kelimeler dosya yollarıdır. Fonksiyonu geçmişi açmadan önce tanımladık ki listeye girmesin. ^nginx^apache yalnızca ilk eşleşmeyi değiştirdi; tüm eşleşmeler için :gs gerekir. Hızlı değiştirme, satırın ilk karakteri olduğunda çalışan ve ! ile başlamayan tek geçmiş genişletmesidir.
Tırnaklar ve "event not found" hatası
Geçmiş genişletmesinde tırnak kuralları kabuğun normal kurallarına benzer ama aynı değildir. Ters eğik çizgi ve tek tırnak ! karakterini korur. Çift tırnak korumaz, çünkü çift tırnak içinde de geçmiş genişletmesi yapılır. İki istisna vardır: ! karakterinden hemen sonra boşluk, sekme, satır sonu, = ya da başka bir metakarakter geliyorsa genişletme başlamaz; ayrıca kapanan çift tırnaktan hemen önceki ! de korunmuş sayılır. Etkileşimli kabukta çok sık görülen hatanın nedeni budur:
set -o history -H
echo "Merhaba!"
echo 'Kaydedildi!dikkat'
echo "Kaydedildi!dikkat"
echo "bitti"
# çıktı:
# Merhaba!
# Kaydedildi!dikkat
# ornek.sh: line 4: !dikkat: event not found
# bittiGenişletme başarısız olduğunda o satır hiç çalıştırılmaz. Çözüm, ünlem içeren metni tek tırnağa almak, ünlemi ters eğik çizgiyle kaçırmak ya da geçmiş genişletmesini hiç kullanmıyorsanız ~/.bashrc içinde set +H ile kapatmaktır. Tırnak türlerinin genel kuralları tek tırnak ve çift tırnak farkı yazısında.
Genişletmeyi çalıştırmadan önce görmek için iki güvenli yol vardır. histverify seçeneği açıksa genişletilmiş satır hemen çalıştırılmaz, düzenleme tamponuna geri yüklenir ve Enter tuşuna yeniden basmanızı bekler. :p değiştiricisi ya da history -p komutu ise sonucu yalnızca yazdırır. histreedit açıksa başarısız bir genişletme de düzeltmeniz için satıra geri yüklenir. Bu iki seçenek yalnızca Readline kullanılırken, yani etkileşimli kabukta etkilidir.
fc ile listeleme, düzenleme ve yeniden çalıştırma
fc komutunun iki biçimi vardır. Birinci biçim bir kayıt aralığını listeler (-l) ya da bir düzenleyicide açar ve kaydettiğinizde komutları yazıp çalıştırır. Düzenleyici -e ile verilmezse sırasıyla FCEDIT, EDITOR ve son çare olarak vi kullanılır. -n numaraları gizler, -r sırayı ters çevirir. Aralık uçları sayı (negatifse o anki komuta göre uzaklık) ya da metin (o metinle başlayan son komut) olabilir; listeleme sırasında uç verilmezse son 16 komut gösterilir.
İkinci biçim fc -s [eski=yeni] [komut], seçilen komutta eski metnini yeni ile değiştirip hemen yeniden çalıştırır. Kılavuzun önerdiği alias r='fc -s' ile r son komutu, r 1.0=2.0 echo ise echo ile başlayan son komutu değiştirerek tekrarlar. Alias'ların nasıl tanımlandığı Bash alias tanımlama yazısında.
set -o history
echo "sürüm 1.0 hazır"
printf '%s\n' ---
fc -s 1.0=2.0 echo
fc -ln -2
# standart hata: echo "sürüm 2.0 hazır"
# çıktı:
# sürüm 1.0 hazır
# ---
# sürüm 2.0 hazır
# printf '%s\n' ---
# echo "sürüm 2.0 hazır"
fc -s yeniden çalıştırdığı komutu listeye kendi yerine kaydeder; bu yüzden fc -ln -2 çıktısında fc -s satırı değil, çalıştırılan echo komutu görünüyor. Liste satırlarının başındaki boşluklar fc çıktısının biçimidir.
Geçmişte arama: Ctrl-R
Etkileşimli kabukta en çok kullanılan geçmiş aracı, genişletme ifadeleri değil Readline'ın aramasıdır. Ctrl-R artımlı geriye doğru aramayı başlatır: yazdığınız her karakterle eşleşen en yakın komut gösterilir, tekrar Ctrl-R bir öncekine gider, Enter komutu çalıştırır, Ctrl-G aramayı iptal eder. Alt-. bir önceki komutun son argümanını imlecin olduğu yere ekler; !$ ifadesinin görerek kullanılan karşılığıdır. Bu tuşların tamamı ve yukarı ok ile önek araması kurmak klavye kısayolları ve Readline yazısında.
Sık yapılan hatalar

- HISTIGNORE desenini önek sanmak: desen satırın tamamıyla eşleşmelidir; önek için sona
*ekleyin. - histappend olmadan çok terminal kullanmak: son kapanan kabuk dosyanın üzerine yazar ve diğer oturumların geçmişi kaybolur.
- HISTFILESIZE değerini HISTSIZE değerinden küçük tutmak: liste uzun olsa da dosya her yazmada kısa boya kırpılır.
- Çift tırnak içinde ünlem: etkileşimli kabukta
event not foundverir; tek tırnak kullanın ya daset +Hile kapatın. - Gizli bilgiyi komut satırına yazmak: geçmiş dosyası düz metindir.
history -dile kaydı silebilirsiniz, ama asıl çözüm gizli değeri komut satırına hiç yazmamaktır. - Betikte geçmiş genişletmesi beklemek: etkileşimsiz kabukta geçmiş de genişletme de kapalıdır; betiklerde bunlara dayanmayın.
Sık Sorulan Sorular
Komut geçmişini tamamen nasıl silerim?
history -c bellekteki listeyi temizler. Ardından history -w boş listeyi dosyaya yazar ve diskteki kopyayı da boşaltır. Yalnızca -c çalıştırırsanız, dosya bir sonraki oturumda yeniden yüklenir.
Tek bir komutu geçmişten nasıl kaldırırım?
history ile numarasını bulun ve history -d numara çalıştırın, ardından değişikliğin dosyaya geçmesi için history -w kullanın. Aralık silmek için history -d 10-20 biçimi de vardır.
history çıktısında tarih ve saat nasıl gösterilir?
HISTTIMEFORMAT='%F %T ' satırını ~/.bashrc dosyanıza ekleyin. Zaman damgası yalnızca bu değişken ayarlıyken kaydedilen komutlar için dosyada tutulur; daha eski kayıtların gerçek zamanı bilinmez.
Geçmiş dosyası nerede?
HISTFILE değişkeninin değerindedir, varsayılanı ~/.bash_history. echo "$HISTFILE" ile kendi kabuğunuzdaki değeri görebilirsiniz.
Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.
İlgili içerikler: Bash öğrenme rehberi · Readline kısayolları · PS1 özelleştirme · .bashrc ve .bash_profile · alias tanımlama · shopt seçenekleri · tırnak farkları · Linux loglarını okuma