スクリプトの単一インスタンス、ただし同じ引数のみ

スクリプトの単一インスタンス、ただし同じ引数のみ

ここに、別のインスタンスが実行されている場合にスクリプトを終了する、すばらしい小さなコードがあります。

single_instance(){
    if pidof -x "${0##*/}" -o %PPID >/dev/null; then
        exit 0
    fi
}

しかし、私が探しているのは、スクリプトが実行された場合にのみ終了する関数です。同じ引数で呼び出される

解決策を自分で見つけられることはわかっていますが、、などcat | grep | awk | cut | sed | tac | sort | uniqのユーティリティを使用してこれを行う簡単な方法があるかどうか疑問に思っていますpidofps

これをどうやって実行しますか?

答え1

次のようなことができます:

#!/bin/bash

single_instance() {

   pid=$(pidof -x "${0##*/}" -o %PPID)

   if [[ $(xargs -0 < /proc/$pid/cmdline) == $@ ]]
   then
       echo QUITTING
       exit 1
   fi
}

single_instance $(xargs -0 < /proc/$$/cmdline)

while :
do
    sleep 10
done

答え2

@goldilocks のコードをいくつか勉強して追加した後、これを思いつきましたman ps。スペースを含む引数を適切に処理し、スクリプトが次のように呼び出された場合にも機能しますbash scriptname

single_instance(){
    if ps -efww | grep "$(ps -o cmd= -p $$)$" | grep -vq " $$ "; then
        exit 0
    fi
}

答え3

fn() { IFS='
';  set -- $(ps -o args= -C "${0##*/}")
    unset IFS
    [ $(($(printf $(printf %s\\n "$@" | sort | uniq -c | sort -rn)))) -gt 1 ] &&
        exit 0
}

同じ引数で呼び出されたexit 02 つ以上のプロセスが現在実行されている場合に発生します。$0

答え4

使用/proc:

single_instance(){

   local tl=$(cat /proc/$$/cmdline)
   local l

   tl=${tl##*/}

   for pid in $(pidof -x "${0##*/}" -o %%PPID); do
        l=$(cat /proc/$pid/cmdline)
        if [ ${l##*/} = $tl ]; then
            echo "already running..."
            exit 0
        fi
    done
}

起動パスなしでコマンドライン間の正確な比較を行います (スクリプトで行ったように)。/proc/*/cmdline値にはスペースが含まれていないため、直接比較できます。ただし、パラメータの順序が変更されても、認識されません。

関連情報