Son çıktı satırını bash içinde nasıl yürütebilirim?


12

Son komutu bash ile çalıştırabileceğimi biliyorum !!, ama son çıkış satırını nasıl çalıştırabilirim?

Bu çıktının kullanım durumunu düşünüyorum:

The program 'git' is currently not installed. You can install it by typing:
sudo apt-get install git

Ama bunu nasıl yapabileceğimi bilmiyorum. !!Belki @@ya da benzeri bir şey mi düşünüyorum ?


Süper Kullanıcı'nın da bu sorusu var.


1
Neden sadece kopyalayıp yapıştırmıyorsun?
Pilot6

1
@Tim Bir programın çıktısının son satırını çalıştırmanın yollarını istersiniz, ancak bu özel kullanım durumu için command_not_found_handlekabuk işlevini veya çalıştırdığı bir komut dosyasını (genellikle sadece /usr/lib/command-not-found) değiştirme yaklaşımı da vardır . Paketi otomatik olarak yükleme seçeneği ile etkileşimli olarak sorulmasını veya (muhtemelen daha iyi), böylece paket adının bir yerde saklanması ve kısa bir komut çalıştırılarak yüklenebileceğini düşünüyorum. Bu, burada sorduğunuzdan yeterince farklı, bu konuda ayrı bir soru göndermeyi düşünebilirsiniz.
Eliah Kagan


2
Ayrıca alakalı olabilir: github.com/nvbn/thefuck (Adı yoksay) bu araç otomatik olarak git / apt / etc komutlarını düzeltir :)
bhathiya-perera

Yanıtlar:


17

Komut $(!! |& tail -1)şunları yapmalıdır:

$ git something
The program 'git' is currently not installed. You can install it by typing:
sudo apt-get install git

$ $(!! |& tail -1)
$(git something |& tail -1)
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following extra packages will be installed:
git-man liberror-perl

Gördüğünüz gibi sudo apt-get install gitkomut çalışıyor.

EDIT: yıkmak$(!! |& tail -1)

  • $()bir bashkomut ikame paterni

  • bash!!son yürütülen komuta genişletilecek

  • |&kısmı zor. Normalde boru |sol taraflı komuta STDOUT alıp sağ tarafındaki komuta STDIN olarak geçecek |önceki komut bir hata mesajı olarak STDERR üzerindeki çıktıyı baskı sizin durumda. Yani, yapmak |yardımcı olmaz, hem STDOUT hem de STDERR'yi (veya sadece STDERR) sağ taraflı komuta geçirmeliyiz. |&STDOUT ve STDERR, STDIN olarak sağ taraftaki komuta geçecektir. Alternatif olarak, sadece STDERR'yi geçmeniz daha iyi:

    $(!! 2>&1 >/dev/null | tail -1)
  • tail -1her zamanki gibi girişinden son satırı basacaktır. Burada, son satırı yazdırmak yerine, apt-get installkomutu içeren satırı yazdırmak gibi daha hassas olabilirsiniz :

    $(!! 2>&1 >/dev/null | grep 'apt-get install')

1
Yaklaşımınız, çıktının ikinci kez aynı olacağını varsayar. Bazı komutlar bir dahaki sefere farklı bir çıktı üretebilir, bu durumda çıktısının son satırının gerçekte ne yapacağını tahmin etmek çok zordur.
kasperd

1
@kasperd Haklısınız ... bu özel örnek söz konusu olduğunda, çıktı aynı kalmalıdır ..
heemayl

7

TL; DR: alias @@='$($(fc -ln -1) |& tail -1)'

Bash'in tarih etkileşim tesisleri , komutların çıktısını incelemek için herhangi bir mekanizma sunmaz . Kabuk bunu depolamaz ve geçmiş genişletmesi özellikle kendiniz çalıştırdığınız komutlar veya bu komutların parçaları içindir.

Bu yapraklar hem son komutu yeniden çalıştırmadan ve borulama yaklaşım stdout'u ve stderr'yi ( |&komut ikamesi içine). heemayl'ın cevabı bunu başarır, ancak bir takma adda kullanılamaz çünkü kabuk takma adları genişletmeden önce tarih genişlemesi yapar ve sonra değil.

Tarih genişleme işleviyle etkinleştirerek bile bir kabuk işlevinde çalışmak için alamıyorum set -H. !!Bir fonksiyonda asla genişletilmeyeceğinden şüpheleniyorum ve eğer olsaydı neye genişletileceğini bilmiyorum, ama şu anda neden tam olarak neden olmadığından emin değilim .

Bu nedenle, bunu çok az yazarak yapabilmeniz için bir şeyler ayarlamak istiyorsanız , geçmiş komutundan son komutu çıkarmak için geçmiş genişletmesi yerine fckabuk yerleşimini kullanmalısınız. Bu, geçmiş genişletmesi devre dışı bırakıldığında bile çalışmasının ek avantajına sahiptir.

Görüldüğü gibi Gordon Davisson 'ın cevabı için bash geçmişi genişlemesini içeren bir takma ad oluşturma (on Super User ) $(fc -ln -1)Simülasyonu yapılan !!. Bu takarak !!içinde heemayl emri $(!! |& tail -1) verim:

$($(fc -ln -1) |& tail -1)

Bu şu şekilde çalışır, $(!! |& tail -1)ancak bir takma ad tanımında gidebilir:

alias @@='$($(fc -ln -1) |& tail -1)'

Eğer bu tanımı çalıştırmak veya koyun sonra .bash_aliasesya .bashrcyeni bir kabuk başlatmak, sadece yazabilirsiniz @@son komutun çıktısı son satırı yürütmek teşebbüs (veya takma adlı neyse).

ek@Io:~$ alias @@='$($(fc -ln -1) |& tail -1)'
ek@Io:~$ evolution
The program 'evolution' is currently not installed. You can install it by typing:
sudo apt-get install evolution
ek@Io:~$ @@
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following extra packages will be installed:
  evolution-common evolution-data-server evolution-data-server-online-accounts
....

Bunu ayrı bir komut dosyasına taşımak için herhangi bir seçenek var mı? Bunu denedim ve nihayet başarısız oldu, çünkü fc hiçbir şey çıkarmıyor ... fc geçerli kabuk oturumunun geçmişini takip ettiğinden, ayrı bir komut dosyasına taşımak, orada boş geçmişe sahip farklı bir oturum açar, tabii ki ... komut dosyasındaki fc satırının üstündeki komutları kullanır ve bunlardan biri yürütülür. Bu yüzden, senaryoya "bağlamının" bash oturumu olduğunu söyleyen herhangi bir seçenek olup olmadığını merak ediyorum. #! / Bin / bash ya da
Exterminator13

Exterminator13 @ Eğer o ayrı komut dosyası demek durumunda çalıştırmak --like ./scriptile değil sen misin kaynağı .veya sourceyerleşik - Özür emin. Bash kabuk Çıkışta bir dosyaya ekler veya çalıştırdığınızda historyile -aveya -w(bkz help history). Eğer öyleyse, çoklu etkileşimli kabuklardaki komutlar araya eklenir (bunları çalıştırdığınız sırayla görüntülenir). Hemen eklenmesini sağlayabilirsiniz. . Ama bence fcsenaryoda çalışacak daha çok şey var . Bununla ilgili yeni bir soru göndermenizi öneririm. Bunu yaparsanız, lütfen buraya bir bağlantıyla yorum yapmaktan çekinmeyin.
Eliah Kagan

2

X altında bir terminal emülatörü kullanıyorsanız veya gibi gnome-terminal, X seçimini kopyala ve yapıştır gibi bir şey için kullanabilirsiniz:konsolexterm

Birincil seçimi kullanma

Üçlü sol tıklama ile çalışacak tüm çizgiyi seçin .

Ardından komut satırına yapıştırın bir kullanan orta düğmesi tıklaması .

Bu, çoğu terminal emülatöründe çalışmalıdır. Panoya dokunmadan birincil seçimi kullanır - bunlar ayrıdır.
Teknik olarak, tek bir işlemde kopyalama ve yapıştırma işlemlerini seçer ve birleştirir.


1
@ Zaman Doğru - Bunu netleştireceğim.
Volker Siegel

1

Eliah Kagan'ın belirttiği gibi, kabuk komut çıktısını saklamaz. Ancak, çıktının son komutun son hat almak için bir yolu yoktur tekrar komutu çalıştırmadan koşarsan, ekranı .

Aşağıdaki satırları size koyun ~/.screenrc:

register t "^a[k0y$ ^a]^a^L"
bind t process t

Ardından , geçerli istemde önceki satırı eklemek için Ctrl+ tuşuna basabilirsiniz at. Bunu otomatik olarak enter tuşuna basmak da mümkün olabilir, ancak çalıştırmadan önce kontrol etmek ve manuel olarak enter tuşuna basmak daha iyi bir fikir olabilir.

Nasıl çalışır:

  • register tbir dizeyi adlı bir ara belleğe kaydeder t. Bunu izleyen dize bir anahtar dizidir.
  • bind tanahtara bağlanır t(yani Ctrl+ kullanarak yürüt at), process tadlandırılan arabellek içeriğini değerlendirmek anlamına gelir t.
  • Dizinin kendisi şu anlama gelir:
    • ^a[(= Ctrla[): kopya moduna gir
    • kbir satır yukarı 0git, satırın başına git, satır y$sonuna kadar kopyala, (boşluk) komutu tamamla
    • ^a](= Ctrla]): kopyalanan içeriği yapıştırın
    • ^a^L(= CtrlaCtrlL) ekranı yenileyin (aksi takdirde yapıştırılan içerik görünmez, çünkü siz kendiniz yazmadınız

0

TL; DR:secondlast Son komutun çıkış satırını çalıştırmanız gerekiyorsa :

alias @@='$($(fc -ln -1) |& tail -2 | head -1)'

Ubuntu 19.10'da, bir komut bulunamadığında ve sudo apt installkomut görüntülendiğinde, sonraki komut isteminden önce boş bir satır vardır, bu nedenle kullanırken hiçbir şey olmaz:alias @@='$($(fc -ln -1) |& tail -1)'

net@net:~$ pip install -e ".[uvloop]"

Command 'pip' not found, but can be installed with:

sudo apt install python-pip

net@net:~$ @@
net@net:~$

Bu durumda secondlast, son komutun çıktı satırını almanız gerekir : alias @@='$($(fc -ln -1) |& tail -2 | head -1)'

    net@net:~$ pip install -e ".[uvloop]"                                                                  

Command 'pip' not found, but can be installed with:

sudo apt install python-pip

net@net:~$ @@
[sudo] password for net: 
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following additional packages will be installed:
...
...
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.