Sizi içine çeken gerçek komutu nasıl belirliyorsunuz?


9

Diyelim ki benim bir bash senaryom var log.sh. Bu komut dosyasında, bir kanaldan girdi okumak istiyorum, ama aynı zamanda bana girdi eklemek için kullanılan komutu da bilmek istiyorum. Misal:

tail -f /var/log/httpd/error | log.sh

Kabuk betiğinde komutu bilmek istiyorum tail -f /var/log/httpd/error.


Bunu neden istediğini çok merak ediyorum.
Ignacio Vazquez-Abrams

Sanırım pids yakalayan ve işleyen GUI programı bir tür yapmak?
palbakulich

Sonuçları nereye koyacağımı ayırt edebilmek için bilmek istiyorum. Komut ve dosya adına bağlı olarak, farklı eylemler gerçekleştirmek istiyorum.
St.John Johnson

4
Bana En Az Sürpriz İlkesi'nin büyük bir ihlali gibi geliyor. Betiğin farklı koşullar altında farklı şeyler yapması gerekiyorsa, girdisinin nereden geldiğinden ziyade bir komut satırı seçeneğiyle denetlenmelidir.
Dave Sherohman

@Dave, katılıyorum. Diyelim ki, bu örnek uğruna, sadece gelen komutun ne olduğunu 'bilmek' istiyorum.
St.John Johnson

Yanıtlar:


7

Akira kullanılmasını önerdi lsof.

Komut dosyasını şu şekilde yazabilirsiniz:

whatpipe2.sh

#!/bin/bash

pid=$$
pgid=$(ps -o pgid= -p $pid)
lsofout=$(lsof -g $pgid)
pipenode=$(echo "$lsofout" | awk '$5 == "0r" { print $9 }')
otherpids=$(echo "$lsofout" | awk '$5 == "1w" { print $2 }')
for pid in $otherpids; do
    if cmd=$(ps -o cmd= -p $pid 2>/dev/null); then
        echo "$cmd"
        break
    fi
done

Koşu:

$ tail -f /var/log/messages | ./whatpipe2.sh
tail -f /var/log/messages
^C

Başka bir yol ise süreç gruplarını kullanmaktır.

whatpipe1.sh

#!/bin/bash    

pid=$$
# ps output is nasty, can (and usually does) start with spaces
# to handle this, I don't quote the "if test $_pgrp = $pgrp" line below
pgrp=$(ps -o pgrp= -p $pid)
psout=$(ps -o pgrp= -o pid= -o cmd=)
echo "$psout" | while read _pgrp _pid _cmd; do
    if test $_pgrp = $pgrp; then
        if test $_pid != $pid; then
            case $_cmd in
            ps*)
                # don't print the "ps" we ran to get this info
                # XXX but this actually means we exclude any "ps" command :-(
                ;;
            *)
                echo "$_cmd"
                ;;
            esac
        fi
    fi
done

Koşu:

$ tail -f /var/log/messages | ./whatpipe1.sh
tail -f /var/log/messages
^C

Her ikisinin de yalnızca borunun sol tarafındaki komut psgörmek için yeterince uzun süre çalıştığında çalıştığını unutmayın . Bunu kullandığınızı söylediniz tail -f, bu yüzden bunun bir sorun olduğundan şüpheliyim.

$ sleep 0 | ./whatpipe1.sh 

$ sleep 1 | ./whatpipe1.sh
sleep 1

Bu büyük yazı yerine ben lsof tabanlı komut dosyası ile 2 yanıt verirdim. bunun için iyi iş.
akira

@akira Teşekkürler. Temiz ve taşınabilir hale getirmek için birkaç girişimde bulundu. Yol boyunca procfs ve lsof hakkında birkaç şey öğrendim. Fikir için teşekkürler.
Mikel

Başkalarının doğrudan kullanabileceği bir cevap verdiği için seninkini kabul ettim. @Akira, işin çoğunu yaptın, üzgünüm seninkini de kabul edemedim.
St.John Johnson

10

boru, işleminizin açık dosya tanımlayıcıları listesinde bir giriş olarak görünür:

 % ls -l /proc/PID/fd
 lr-x------ 1 xyz xyz 64 Feb 11 08:05 0 -> pipe:[124149866]
 lrwx------ 1 xyz xyz 64 Feb 11 08:05 1 -> /dev/pts/2
 lrwx------ 1 xyz xyz 64 Feb 11 08:05 2 -> /dev/pts/2
 lr-x------ 1 xyz xyz 64 Feb 11 08:05 10 -> /tmp/foo.sh

ayrıca şöyle bir şey kullanabilirsiniz:

 % lsof -p PID
 sh      29890 xyz  cwd    DIR   0,44    4096  77712070 /tmp
 sh      29890 xyz  rtd    DIR   0,44    4096  74368803 /
 sh      29890 xyz  txt    REG   0,44   83888  77597729 /bin/dash
 sh      29890 xyz  mem    REG   0,44 1405508  79888619 /lib/tls/i686/cmov/libc-2.11.1.so
 sh      29890 xyz  mem    REG   0,44  113964  79874782 /lib/ld-2.11.1.so
 sh      29890 xyz    0r  FIFO    0,6         124149866 pipe
 sh      29890 xyz    1u   CHR  136,2                 4 /dev/pts/2
 sh      29890 xyz    2u   CHR  136,2                 4 /dev/pts/2
 sh      29890 xyz   10r   REG   0,44      66  77712115 /tmp/foo.sh

böylece, borunun inode var daha :) şimdi /proc/o boru için altındaki diğer tüm işlemleri arayabilirsiniz . o zaman size piping yapan bir komuta sahip olacaksınız:

 % lsof | grep 124149866 
 cat     29889 xyz    1w  FIFO                0,6          124149866 pipe
 sh      29890 xyz    0r  FIFO                0,6          124149866 pipe

bu örnekte, catkoğuşlara bağlanmıştır sh. içinde tam olarak adlandırılan /proc/29889dosyayı cmdlinesöyleyen bir dosya bulabilirsiniz :

 % cat /proc/29889/cmdline
 cat/dev/zero%  

komut satırının alanları NUL ile ayrılır, bu yüzden biraz çirkin görünüyor :)


Hangi cevabı kabul edeceğimi bilmiyorum. @Akira, nasıl belirleneceğine dair gerçek dökümü verdin, @Mikel bana bir senaryo verdi. İşleri harika + zor hale getirmenin yolu.
St.John Johnson

1

İşte lsofmodern Linux dağıtımlarında modern kullanan kompakt bir çözüm :

cmd=$(lsof -t -p $$ -a -d 0 +E | while read p; do
    [ $p -ne $$ ] && echo "$(tr \\000 " " </proc/$p/cmdline)"
done)

Bu +E, geçerli kabuk işlemindeki ( -p $$ -a -d 0) FD 0'ın son nokta dosyalarını ( ) listeler , ardından çıkışı yalnızca PID'lerle ( -t) sınırlandırır ve borunun her iki tarafındaki PID'leri verir.

Bunu not et:

  1. Kaynak ucunda birden fazla PID bulunabilir, örneğin { echo Hi; sleep 5 ; } | whatpipe.shbüyük olasılıkla a bash(giriş alt kabuğu) ve sleep 5.
  2. +Eyalnızca lsofderlenmişse kullanılabilir -DHASUXSOCKEPT. Çoğu modern Linux dağıtımı için bu doğru olmalı, ancak kurulumunuzu yine de şunlarla kontrol edin:lsof -v 2>&1 | grep HASUXSOCKEPT
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.