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.