आप उस वास्तविक कमांड को कैसे निर्धारित करते हैं जो आप में पाइपिंग कर रहा है?


9

मान लीजिए कि मेरे पास एक बैश स्क्रिप्ट है जिसे कहा जाता है log.sh। इस स्क्रिप्ट में, मैं एक पाइप से इनपुट में पढ़ना चाहता हूं, लेकिन मैं यह भी जानना चाहता हूं कि मेरे द्वारा इनपुट करने के लिए किस कमांड का इस्तेमाल किया गया है। उदाहरण:

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

शेल स्क्रिप्ट में, मैं कमांड जानना चाहता हूं tail -f /var/log/httpd/error


मैं बेहद उत्सुक हूं कि आप ऐसा क्यों चाहते हैं।
इग्नासियो वाज़केज़-अब्राम्स

मेरा अनुमान है कि आपके कुछ प्रकार के GUI प्रोग्राम हैं जो कैप्चर और प्रक्रियाएं करते हैं?
पालबुलिच

मैं जानना चाहूंगा ताकि मैं यह पता लगा सकूं कि परिणाम कहां रखे जाएं। आदेश और फ़ाइल नाम के आधार पर, मैं विभिन्न क्रियाएं करना चाहूंगा।
सेंट जॉन जॉनसन

4
यह मुझे आश्चर्य का सिद्धांत का एक बड़ा उल्लंघन की तरह लगता है। यदि स्क्रिप्ट को अलग-अलग परिस्थितियों में अलग-अलग चीजें करनी चाहिए, तो इसका इनपुट कमांड-लाइन विकल्प द्वारा नियंत्रित किया जाना चाहिए बजाय इसके कि इनपुट कहां से आ रहा है।
डेव शेरोमैन

@ मैं सहमत हूँ। आइए बस इस उदाहरण के लिए कहते हैं, मैं सिर्फ यह जानना चाहता हूं कि आने वाली कमांड क्या है।
सेंट जॉन जॉनसन

जवाबों:


7

अकीरा ने उपयोग करने का सुझाव दिया lsof

यहां बताया गया है कि आप इसे कैसे लिख सकते हैं:

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

इसे चलाना:

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

एक अन्य तरीका प्रक्रिया समूहों का उपयोग कर रहा है।

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

इसे चलाना:

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

ध्यान दें कि वे दोनों केवल तभी काम करते हैं जब पाइप के बाईं ओर कमान psइसे देखने के लिए लंबे समय तक चलती है। आपने कहा कि आप इसका उपयोग कर रहे थे tail -f, इसलिए मुझे संदेह है कि यह एक मुद्दा है।

$ sleep 0 | ./whatpipe1.sh 

$ sleep 1 | ./whatpipe1.sh
sleep 1

इस विशाल पोस्ट के बजाय मैंने lsof- आधारित स्क्रिप्ट के साथ 2 उत्तर दिया होगा। उस एक के लिए अच्छा काम।
अकीरा

@akira धन्यवाद। इसे साफ और पोर्टेबल बनाने के लिए कुछ प्रयास किए गए। रास्ते के बारे में procfs और lsof के बारे में कुछ बातें सीखीं। विचार के लिए धन्यवाद।
मिकेल

मैंने आपका स्वीकार कर लिया क्योंकि यह एक उत्तर देता है जिसका अन्य लोग सीधे उपयोग कर सकते हैं। @ अकीरा, आपने ज्यादातर काम किया, क्षमा करें मैं आपका भी स्वीकार नहीं कर सका।
सेंट जॉन जॉनसन

10

पाइप आपकी प्रक्रिया के खुले दर्जकर्ताओं की सूची में एक प्रविष्टि के रूप में दिखाई देगा:

 % 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

आप भी कुछ इस तरह का उपयोग कर सकते हैं:

 % 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

इसलिए, आपके पास पाइप का इनकोड है :) अब आप /proc/उस पाइप के लिए हर दूसरी प्रक्रिया को खोज सकते हैं । तब आपके पास कमांड होगी जो आपको पाइप कर रही है:

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

इस उदाहरण में, catवार्डों को पाइप किया गया sh/proc/29889आप में एक फाइल मिल सकती है cmdline, जो आपको बताती है, कि वास्तव में क्या कहा गया था:

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

कमांड लाइन के क्षेत्र NUL द्वारा अलग किए गए हैं, इस प्रकार यह थोड़ा बदसूरत दिखता है :)


मुझे नहीं पता कि कौन सा उत्तर स्वीकार करना है। @ अकीरा, आपने वास्तविक ब्रेकडाउन दिया कि इसे कैसे निर्धारित किया जाए, जबकि @ मिकेल ने मुझे एक स्क्रिप्ट दी। चीजों को भयानक + कठिन बनाने का तरीका।
सेंट जॉन जॉनसन

1

यहाँ lsofआधुनिक लिनक्स वितरण पर आधुनिक का उपयोग कर एक कॉम्पैक्ट समाधान है :

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

यह +Eवर्तमान शेल प्रक्रिया ( -p $$ -a -d 0) पर FD 0 के समापन बिंदु फ़ाइलों ( ) को सूचीबद्ध करता है , फिर आउटपुट को केवल PIDs तक सीमित करता है ( -t), पाइप के दोनों तरफ PIDs की उपज।

ध्यान दें कि:

  1. वहाँ पीआईडी स्रोत अंत पर पाया एक से अधिक है, जैसे हो सकता है { echo Hi; sleep 5 ; } | whatpipe.shसंभावना एक निकलेगा bash(इनपुट subshell) और sleep 5
  2. +Eकेवल तभी उपलब्ध है जब lsofइसके साथ संकलित किया गया था -DHASUXSOCKEPT। यह सबसे आधुनिक लिनक्स डिस्ट्रोस के लिए सही होना चाहिए, लेकिन इसके साथ अपने इंस्टॉलेशन की जाँच करें:lsof -v 2>&1 | grep HASUXSOCKEPT
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.