İki komutun çıktısını nasıl değiştirebilirim?


165

İki benzer dizinin içeriğini karşılaştırmanın en basit yolunun böyle olacağını düşünmüştüm.

diff `ls old` `ls new`

Fakat bunun neden işe yaramadığını anlıyorum; diffUmduğum gibi iki akış yerine, komut satırında çok uzun bir dosya listesi veriliyor. İki çıkışı doğrudan dağıtmak için nasıl iletirim?


Yanıtlar:


246

Komut değiştirme `…`komutu, komutun çıktısını komut satırının yerine koyar, bu nedenle diffher iki dizindeki dosyaların listesini argüman olarak görür. İstediğiniz şey diff, komut satırında iki dosya adı görmek ve bu dosyaların içeriğinin dizin listeleri olması. İşlem değişimi budur .

diff <(ls old) <(ls new)

Şunun diffgibi görünecek argümanlar /dev/fd/3ve /dev/fd/4bunlar: bash tarafından oluşturulan iki boruya karşılık gelen dosya tanımlayıcılarıdır. Ne zaman diffbu dosyaları açar, her borunun okuma tarafına bağlanırsınız. Her borunun yazma tarafı lskomuta bağlanır .


49
echo <(echo) <(echo)bunun bu kadar ilginç olabileceğini hiç düşünmemiştim: D
Kova Gücü

3
İşlem değiştirme tüm kabuklar tarafından desteklenmez , ancak boru yönlendirmeleri temiz bir geçici çözümdür .
Irfan434

1
Sadece ls ayrıştırma tavsiye edilmez belirtmeyi unix.stackexchange.com/questions/128985/why-not-parse-ls
katu

@Katu Sorun, lsdosya adlarını düzenlemesidir. Çıktısını ayrıştırma kırılgandır (“garip” dosya adları ile çalışmaz). İki dizin listesini karşılaştırmak için, çıktı açık olduğu sürece sorun yok. İsteğe bağlı dosya isimleri ile bunun gibi bir seçenek gerekir --quoting-style=escape.
Gilles

1
@will <(…)bir boru oluşturur. Görünüşe göre meld borularla çalışmıyor, kullanamazsın <(…). Zsh, değiştirmek olabilir <(…)tarafından =(…)ve çünkü çalışacak =(…)geçici bir dosyada ara çıktıları koyar. Kısaca, uygun bir sözdizimi olduğunu sanmıyorum, geçici dosyaları kendiniz yönetmek zorunda kalacaksınız.
Gilles

3

Zsh için, =(command)otomatik olarak kullanmak geçici bir dosya oluşturur ve dosyanın =(command)yolunun yerine geçer . Komut Değiştirme $(command)ile , komutun çıktısı ile değiştirilir .

Yani üç seçenek var:

  1. Komut Değiştirme: $(...)
  2. İşlem Değiştirme: <(...)
  3. zsh-Aromalı Proses Değişimi: =(...)

zsh aromalı işlem değişimi, # 3, çok kullanışlıdır ve bir diff aracı kullanarak iki komutun çıktısını karşılaştırmak için bu şekilde kullanılabilir, örneğin Beyond Compare:

bcomp  =(ulimit -Sa | sort) =(ulimit -Ha | sort)

Karşılaştırma Ötesi bcompiçin , karşılaştırmayı başlattığından ve tamamlanmasını beklediğinden yukarıdakiler yerine (yerine bcompare) kullanmanız gerektiğini unutmayın . Eğer kullanırsanız , o karşılaştırmayı başlatır ve hemen hangi komutların çıktısını depolamak için oluşturulan geçici dosyalar kaybolur nedeniyle çıkar.bcompbcompare

Daha fazlasını buradan okuyun: http://zsh.sourceforge.net/Intro/intro_7.html

Ayrıca şunu fark et:

Kabuğun geçici bir dosya oluşturduğunu ve komut tamamlandığında dosyayı sildiğini unutmayın.

ve zsh (yani # 2 ve # 3) tarafından desteklenen iki tür Proses ikamesi arasındaki fark olanları:

Zsh'ın man sayfasını okursanız, <(...) 'ın = (...)' a benzeyen başka bir işlem ikame şekli olduğunu fark edebilirsiniz. İkisi arasında önemli bir fark var. <(...) durumunda, kabuk bir dosya yerine adlandırılmış bir boru (FIFO) oluşturur. Bu daha iyidir, çünkü dosya sistemini doldurmaz; ama her durumda işe yaramaz. Aslında, yukarıdaki örneklerde = (...) yerine <(...) ile yer değiştirmiş olsaydık, fgrep -f <(...) dışında hepsi çalışmazdı. Bir boruyu düzenleyemez veya bir posta klasörü olarak açamazsınız; Bununla birlikte, fgrep, bir borudan kelimelerin bir listesini okumakla ilgili bir problemi yoktur. Diff <(foo) bar'ın neden çalışmadığını merak edebilirsiniz, çünkü foo | diff - bar çalışmaları; Bunun nedeni, diff'in argümanlarından birinin - olduğunu fark etmesi durumunda geçici bir dosya yaratması ve ardından standart girişini geçici dosyaya kopyalamasıdır.

Referans: https://unix.stackexchange.com/questions/393349/difference-between-subshells-and-process-substitution


2
$(...)işlem değiştirme değil, komut değiştirme. <(...)süreç ikamedir. Bu yüzden kote edilen pasajdan hiç bahsetmiyor $(...).
muru

2

Balık kabuğu

Balık kabuğundaki psub içine boru gerekir . Beyond Compare ile bir heroku ve dokku config karşılaştırması örneği :

bcompare (ssh me@myapp.pl dokku config myapp | sort | psub) (heroku config -a myapp | sort | psub)

1
Bir başka grafiksel fark aracı ise meldUbuntu ve EPEL depolarında açık kaynak kodlu ve açık kaynaklıdır. meldmerge.org
phiphi

0

Genellikle kabul edilen cevaplarda açıklanan tekniği kullanırım:

diff <(ls old) <(ls new)

ama genellikle yukarıdaki örnekten çok daha karmaşık komutlarla kullandığımı görüyorum. Bu gibi durumlarda, diff komutunun oluşturulması can sıkıcı olabilir. Başkalarının yararlı bulabileceği bazı çözümler buldum.

Zaman zaman% 99'unu diff çalıştırmadan önce ilgili komutları denediğimi anlıyorum. Sonuç olarak, yaymak istediğim komutlar tarihçemde tam orada ... neden kullanmıyorsunuz?

Son iki komutu yerine getirmek için Fix Command (fc) bash komutunu kullanıyorum:

$ echo A
A
$ echo B
B
$ diff --color <( $(fc -ln -1 -1) ) <( $(fc -ln -2 -2 ) )
1c1
< B
---
> A

Fc bayrakları:

-n : Numara yok. Listeleme sırasında komut numaralarını gizler.

-l : Liste: Komutlar standart çıktıda listelenmiştir.

bu -1 -1, tarihteki başlangıç ​​ve bitiş konumlarına atıfta bulunur; bu durumda, son komuttan, yalnızca son komutu veren son komuta kadar.

Son olarak $(), komutu bir alt kabukta çalıştırmak için bunu sarıyoruz.

Açıkçası bu, biraz takma addır, bu yüzden bir takma ad oluşturabiliriz:

alias dl='diff --color <( $(fc -ln -1 -1) ) <( $(fc -ln -2 -2 ) )'

Veya bir fonksiyon yaratabiliriz:

dl() {
    if [[ -z "$1" ]]; then
        first="1"
    else
        first="$1"
    fi
    if [[ -z "$2" ]]; then
        last="2"
    else
        last="$2"
    fi
    # shellcheck disable=SC2091
    diff --color <( $(fc -ln "-$first" "-$first") ) <( $(fc -ln "-$last" "-$last") )
}

hangi kullanmak için tarih satırlarının belirlenmesini destekler. İkisini de kullandıktan sonra, takma adı tercih ettiğim sürüm buluyorum.

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.