Instância única do script, mas apenas com os mesmos argumentos

4

Eu tenho esse pequeno código aqui que sairá de um script se houver outra instância dele em execução:

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

Mas o que estou procurando é uma função que sairá somente se o script tiver sido chamado com os mesmos argumentos .

Eu sei que eu poderia hackear meu caminho com uma solução cat | grep | awk | cut | sed | tac | sort | uniq , mas gostaria de saber se existe uma maneira simples de fazer isso com utilitários como pidof , ps , etc.

Como você faria isso?

    
por Teresa e Junior 22.06.2014 / 17:24

4 respostas

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

Isso representará exit 0 se dois ou mais processos $0 estiverem em execução e forem invocados com os mesmos argumentos.

    
por 22.06.2014 / 18:55
3

Você pode fazer algo assim:

#!/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
    
por 22.06.2014 / 18:43
3

Eu inventei isso depois de estudar man ps e adicionar algum código de @goldilocks. Ele faz um bom trabalho ao manipular argumentos com espaços e também funciona se o script for chamado como bash scriptname :

single_instance(){
    if ps -efww | grep "$(ps -o cmd= -p $$)$" | grep -vq " $$ "; then
        exit 0
    fi
}
    
por 22.06.2014 / 17:58
2

Usando / 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
}

Ele faz uma comparação exata entre linhas de comando sem o caminho de inicialização (como você fez no seu script). Os valores de /proc/*/cmdline não possuem nenhum espaço, por isso você pode consultá-los diretamente. Se a ordem dos parâmetros for alterada, não será percebida.

    
por 22.06.2014 / 18:18