Dash'te Süreç Değişimi nasıl taklit edilir?


18

İçinde bash, süreç değiştirme kullanın ve bir diske kaydedilmiş bir dosya gibi bir işlem çıktısını tedavi:

$ echo <(ls)
/dev/fd/63

$ ls -lAhF <(ls)
lr-x------ 1 root root 64 Sep 17 12:55 /dev/fd/63 -> pipe:[1652825]

maalesef, Süreç Yedeği desteklenmiyor dash.

Kısa sürede taklit etmenin en iyi yolu ne olurdu Process Substitution?

Çıkışı bir yere geçici bir dosya olarak kaydetmek istemiyorum ( /tmp/) ve sonra silmek zorundayım. Alternatif bir yol var mı?


Ne yapmaya çalıştığınıza bağlı olarak boruları kullanabilirsiniz.
Eric Renouf

Dürüst olmak gerekirse, taşınabilirlik ana endişeniz değilse bash, cihazınıza yüklemek daha kolay olmaz mıydı ?
Arkadiusz Drabczyk

1
Ödül bildiriminde verdiğiniz örnek, bu bağlantılı cevabın konusudur . Orada gösterildiği gibi, Gilles'in cevabının basitleştirilmiş bir versiyonu ( yerine /dev/fdkullanılabilirliği ve kullanımı varsayarak ) olabilir . xz -cd <file>cat <file> | xz -dxz -cd "$1" | { xz -cd "$2" | { diff /dev/fd/3 /dev/fd/4; } 3<&0; } 4<&0
fra-san

1
@ fra-san - aslında ihtiyacım olan buydu. İsterseniz cevaplayabilirsiniz. Teşekkürler.
Martin Vegter

Yanıtlar:


4

Mevcut ödül bildirimindeki soru:

genel örnek çok karmaşıktır. Birisi lütfen aşağıdaki örneğin nasıl uygulanacağını açıklayabilir mi?diff <(cat "$2" | xz -d) <(cat "$1" | xz -d)

burada bir cevap var gibi görünüyor .

Gilles'in cevabında gösterildiği gibi , genel fikir, "üretici" komutlarının çıktısını , bir boru hattının farklı aşamalarında yeni cihaz dosyalarına ( 1) göndermek ve bunları, dosya adlarını bağımsız değişken olarak alabilecekleri "tüketici" komutları için kullanılabilir hale getirmektir ( sisteminizin size dosya tanımlayıcılarına erişim izni verdiği varsayılarak /dev/fd/X)

Aradığınızı elde etmenin en basit yolu muhtemelen:

xz -cd file1.xz | { xz -cd file2.xz | diff /dev/fd/3 -; } 3<&0

(Kullanma file1.xzyerine "$1"okunabilmesi için ve xz -cdyerine cat ... | xz -dtek bir komut yeterli olduğu için).

Birinci "üretici" komutunun çıktısı, xz -cd file1.xzbir bileşik komutuna ( {...}) bağlanır ; ancak, bir sonraki komutun standart girdisi olarak hemen tüketilmek yerine, dosya tanımlayıcısına çoğaltılır3 ve böylece bileşik komutunun içindeki her şeye erişilebilir olur /dev/fd/3. xz -cd file2.xzNe standart girdisini ne de dosya tanımlayıcısından herhangi bir şeyi tüketmeyen ikinci "üretici" komutunun çıktısı 3, daha sonra diffstandart girdisinden ve okunan "tüketici" komutuna bağlanır /dev/fd/3.

Borulama ve dosya tanımlayıcı çoğaltması, gerektiği kadar "üretici" komutu için aygıt dosyaları sağlamak amacıyla eklenebilir, örn:

xz -cd file1.xz | { xz -cd file2.xz | { diff /dev/fd/3 /dev/fd/4; } 4<&0; } 3<&0

Sorunuz bağlamında alakasız olsa da, şunu belirtmek gerekir:

  1. cmd1 <(cmd2) <(cmd3), cmd2 | { cmd3 | { cmd1 /dev/fd/3 /dev/fd/4; } 4<&0; } 3<&0Ve ( cmd2 | ( cmd3 | ( cmd1 /dev/fd/3 /dev/fd/4 ) 4<&0 ) 3<&0 )ilk yürütme ortamında farklı potansiyel etkileri vardır.

  2. Olur aksine cmd1 <(cmd2) <(cmd3), cmd3ve cmd1de cmd2 | { cmd3 | { cmd1 /dev/fd/3 /dev/fd/4; } 4<&0; } 3<&0kullanıcıdan herhangi bir giriş okumak mümkün olmayacaktır. Bunun için daha fazla dosya tanımlayıcı gerekir. Örneğin,

    diff <(echo foo) <(read var; echo "$var")
    

    gibi bir şeye ihtiyacın olacak

    { echo foo | { read var 0<&9; echo "$var" | diff /dev/fd/3 -; } 3<&0; } 9<&0
    

1 Bunlarla ilgili daha fazla bilgiyi U&L'de bulabilirsiniz, örn. Anlama / dev ve alt dizinleri ve dosyaları .


12

Sıhhi tesisatı manuel olarak yaparak kabuğun kaputun altında ne yaptığını çoğaltabilirsiniz. Sisteminizde girişler varsa, dosya tanımlayıcı karıştırma özelliğini kullanabilirsiniz:/dev/fd/NNN

main_command <(produce_arg1) <(produce_arg2) >(consume_arg3) >(consume_arg4)

için

{ produce_arg1 |
  { produce_arg2 |
    { main_command /dev/fd5 /dev/fd6 /dev/fd3 /dev/fd4 </dev/fd/8 >/dev/fd/9; } 5<&0 3>&1 |
    consume_arg3; } 6<&0 4>&1; |
  consume_arg4; } 8<&0 9>&1

Birden çok girişi ve çıkışı göstermek için daha karmaşık bir örnek gösterdim. Standart girdiden okumanız gerekmiyorsa ve işlem ikamesini kullanmanızın tek nedeni, komutun açık bir dosya adı gerektirmesidir, şunları kullanabilirsiniz /dev/stdin:

main_command <(produce_arg1)
produce_arg1 | main_command /dev/stdin

Olmadan , adlandırılmış bir boru kullanmanız gerekir . Adlandırılmış bir kanal bir dizin girdisidir, bu nedenle bir yerde geçici bir dosya oluşturmanız gerekir, ancak bu dosya yalnızca bir addır, veri içermez./dev/fd/NNN

tmp=$(mktemp -d)
mkfifo "$tmp/f1" "$tmp/f2" "$tmp/f3" "$tmp/f4"
produce_arg1 >"$tmp/f1" &
produce_arg2 >"$tmp/f2" &
consume_arg3 <"$tmp/f3" &
consume_arg4 <"$tmp/f4" &
main_command "$tmp/f1" "$tmp/f2" "$tmp/f3" "$tmp/f4"
rm -r "$tmp"

2
</dev/fd/8 >/dev/fd/9<&8 >&9Linux'takine eşdeğer değildir ve bundan kaçınılmalıdır.
Stéphane Chazelas

@Gilles - Karmaşık örnekle kafam karıştı. Lütfen nasıl taklit edileceğini gösterebilir misiniz diff <(cat "$2" | xz -d) <(cat "$1" | xz -d)?
Martin Vegter

3

Birisi lütfen aşağıdaki örneğin nasıl uygulanacağını açıklayabilir mi?
diff <(cat "$2" | xz -d) <(cat "$1" | xz -d)

Ben adlandırılmış borular yönlendirme daha grok için daha basit olduğunu düşünüyorum, yani en basit terimlerle:

mkfifo p1 p2               # create pipes
cat "$2" | xz -d > p1 &    # start the commands in the background
cat "$1" | xz -d > p2 &    #    with output to the pipes
diff p1 p2                 # run 'diff', reading from the pipes
rm p1 p2                   # remove them at the end

p1ve p2geçici olarak adlandırılan borularsa, herhangi bir şey olarak adlandırılabilir.

Boruları /tmp, örneğin Gilles'in cevabının gösterdiği bir dizinde oluşturmak ve catburada ihtiyacınız olmadığını unutmayın , bu yüzden:

tmpdir=$(mktemp -d)
mkfifo "$tmpdir/p1" "$tmpdir/p2"
xz -d < "$2" > "$tmpdir/p1" &
xz -d < "$1" > "$tmpdir/p2" &
diff "$tmpdir/p1" "$tmpdir/p2"
rm -r "$tmpdir"

(Büyük olasılıkla tırnak işaretleri olmadan da kaçabilirsiniz, çünkü mktempbüyük olasılıkla "güzel" dosya adları oluşturur.)

Boru çözümü, ana komut ( diff) tüm girdiyi okumadan önce ölürse, arka plan işlemlerinin asılı bırakılabileceği uyarısına sahiptir .


0

Ne dersin:

cat "$2" | xz -d | diff /dev/sdtin /dev/stderr 2<<EOT
`cat "$1" | xz -d`
EOT
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.