Wijs de uitvoer van 'ps -a -u user -F` toe aan een SHELL-variabele

Ik probeer VNC-sessies hard te maken. Dus ik gebruik zoals hieronder

    STAT = `ps -a -u user -F | grep "Xvnc :" | grep -v grep`

Als de VNC-sessie actief is, is de uitvoer van het commando "ps -a -u-gebruiker -F" meerdere regels. Vervolgens krijgt STAT alle regels toegewezen. Ik ben gewoon geïnteresseerd in slechts ÉÉN regel, want ik wilde alleen dat alle SESSIENUMMERS van VNC voor de "gebruiker" zouden werken. Ik heb de onderstaande opdracht geprobeerd om "@" als mijn scheidingsteken te gebruiken (insteard van "\ n" om STAT te ontleden). Het lijkt niet te werken

    STAT = `ps -a -u user -F | grep "Xvnc :" | grep -v grep | tr -s "\n" "@"

Het enige dat ik nodig heb is om het VNC-sessienummer (s) te pakken. Alle suggesties op prijs gesteld.

0
Met "Session numbers" bedoelt u zoiets als ": 2" ": 3" en dergelijke? (X displaynummers?)
toegevoegd de auteur BRFennPocock, de bron
Geef alsjeblieft een voorbeelduitvoer van het eerste commando en de gewenste uitvoer ervan.
toegevoegd de auteur Rok Strniša, de bron

3 antwoord

Als uw versie van ps dit ondersteunt, is het beter om de uitvoer opnieuw te formatteren zodat deze gemakkelijker te ontleden is. Op mijn systeem kan ik dit doen:

$ ps -o command= -C Xvnc
Xvnc :1

$ ps_output="$(ps -o command= -C Xvnc)"

$ vnc_display="${ps_output#Xvnc :}"

$ echo $vnc_display
1

Natuurlijk heeft deze methode een aantal beperkingen. Het selecteert geen specifieke gebruiker en zal niet werken als u andere opdrachtregelopties gebruikt voor Xnc , of als u meerdere sessies heeft uitgevoerd. In plaats daarvan wilt u misschien iets als dit doen:

$ grep -z "^:" "/proc/$(pgrep -u user Xvnc)/cmdline"
:1

Stel een parameter in met opdrachtvervanging en verwijder eventueel de dubbele punt als u dat wilt. Dit werkt nog steeds niet als een enkele gebruiker meerdere VNC-sessies uitvoert. In plaats daarvan moet je de resultaten van $ (pgrep -u user Xvnc) herhalen. Als je je niet druk maakt om mooi geparseerde resultaten, omdat een mens de resultaten toch verwerkt, kun je dit altijd gewoon doen:

$ ps $(pgrep -u user Xvnc)
  PID TTY      STAT   TIME COMMAND
 3600 pts/2    S      0:00 Xvnc :2
 3606 pts/2    S      0:00 Xvnc :3

De manier waarop dit werkt, is door de opdracht pgrep uit te voeren, die zal zoeken naar processen die voldoen aan de opgegeven criteria (in dit geval wordt uitgevoerd onder gebruiker gebruiker en met de opdrachtnaam Xvnc ). Hier is hoe de uitvoer eruit zou zien:

$ pgrep -u user Xvnc 
3600
3606

Als u dit in $ ( en ) invoert, wordt de opdrachtvervangingsfunctie ingeschakeld. Dit neemt de uitvoer van een commando en vervangt het als onderdeel van je opdrachtregel. (Voer info "(bash) opdrachtvervanging uit" ) voor meer informatie). Wanneer u ps $ (pgrep -u user Xvnc) uitvoert, zorgt het ervoor dat de shell dit als volgt interpreteert:

$ ps 3600 3606

die dezelfde output produceren. U kunt precies zien wat Bash aan het doen is als u de set -x debug-optie gebruikt:

$ set -x
$ ps $(pgrep -u user Xvnc)
++ pgrep -u user Xvnc
+ ps 3600 3606
  PID TTY      STAT   TIME COMMAND
 3600 pts/2    S      0:00 Xvnc :2
 3606 pts/2    S      0:00 Xvnc :3
1
toegevoegd
Natuurlijk, extra uitleg toegevoegd.
toegevoegd de auteur Michael Hoffman, de bron
Geweldig. Kan ik wat uitleg krijgen bij "ps $ (pgrep -u user Xvnc)
toegevoegd de auteur Mike, de bron
erg leuk, dat gaat in mijn gereedschapskist.
toegevoegd de auteur BRFennPocock, de bron

Als u alleen X-weergavenummers wilt hebben (bijvoorbeeld: 1,: 2), kunt u het volgende proberen:

  STAT=`ps -a -u ${USER} -F | \
     perl -ne '$\=" ";if (/^.{64,}Xvnc.*?:([0-9]+)/){print $1}'

This might be a little safer under esoteric conditions, because it skips the first 64 columns of ps output before looking for Xvnc, and the regexp is complex enough that it can't match itself. This will load $STAT with a space-delimited list of X display ID's, e.g. "2 4 6" or similar, suitable for use in for n in $STAT; do echo "$USER is on :$n"; done

(uitgebroken:

   $\=" ";       # print a space after every print command
   if (/^        # start of line (matches the input line 
        .{64,}   # at least 64 characters
        Xvnc     # the bit you wanted
        .*?      # any other spaces or parameters that might be around
        :        # find a colon
        (\d+)    # find, and keep, at least one digit
        /x)      # (the /x only so I can put comments into the regex here)
   { print $1 }  # print the digits that we found in() group 1

and perl -ne puts an automatic while(<>){} loop in place to read the input)

0
toegevoegd
Bedankt voor de geweldige uitleg
toegevoegd de auteur Mike, de bron

Om een ​​lijst met sessienummers te verwerken:

$ for snumber in $(ps -a -u USERNAME -F | grep -o -P '[X]vnc :\d+' | awk -F':' '{ print $2 }'); do echo Session ${snumber}; done
Session 2
Session 1
$ 

Om een ​​lijst van sessienummers in één variabele te hebben:

LIST=$(ps -a -u USERNAME -F | grep -o -P '[X]vnc :\d+' | awk -F':' '{ print $2 }' | tr '\n' ' ' | sed 's; $;;')
0
toegevoegd
Goed antwoord. Dit is een beetje aangepast omdat ik alleen geïnteresseerd ben in sessienummer 8. Veranderde het bovenstaande commando zoals hieronder - ps -a -u cad -F | grep -o -P "Xvnc: \ d +" | grep "Xvnc: 8" - Ik krijg de foutmelding "grep Geen bestand of map en Xvnc. Geen bestand of directcotry
toegevoegd de auteur Mike, de bron
Alle grep-do's is "output" van het deel van de string dat overeenkomt met het patroon "Xvnc: \ d +" => Xvnc gevolgd door: gevolgd door minstens één cijfer. Wat is de MISTAKE die het naar een 'grep' leidt om naar een bepaald 'cijfer' te zoeken uit N aantal Xvnc-sessies?
toegevoegd de auteur Mike, de bron
@Mike: je hebt het duidelijk verkeerd gewijzigd :)
toegevoegd de auteur user405725, de bron
@Mike: het is geen fout, maar kan na uw wijzigingen liggen. Ik zou zeggen lees "man grep" :)
toegevoegd de auteur user405725, de bron