Vraag Een cron-taak handmatig en onmiddellijk uitvoeren


(Ik heb het al gelezen Hoe kan ik een nieuw cron-script testen?.)

Ik heb een specifiek probleem (de cron-taak lijkt niet te worden uitgevoerd of wordt niet correct uitgevoerd), maar het probleem is algemeen: ik wil graag scripts debuggen die worden gecatroneerd. Ik ben me ervan bewust dat ik een * * * * * crontab-regel kan opzetten, maar dat is geen volledig bevredigende oplossing. Ik zou graag een cron-taak vanaf de commandoregel kunnen uitvoeren alsof cron deze zou uitvoeren (dezelfde gebruiker, dezelfde omgevingsvariabelen, enz.). Is er een manier om dit te doen? 60 seconden wachten om scriptwijzigingen te testen is niet praktisch.


94
2017-11-18 13:55


oorsprong


(sorry kan geen commentaar toevoegen) 0 30 16 20 *? * zelfs als je de taak zo uitvoert, is het hele idee om scriptuitvoer te leveren om te zien wat er fout gaat, tenzij de taak naar een log schrijft, dit is nutteloos


antwoorden:


Dit is wat ik deed en het lijkt in deze situatie te werken. Tenminste, het laat me een fout zien, terwijl ik vanaf de commandoregel start als de gebruiker de fout niet toont.


Stap 1: Ik zet deze regel tijdelijk in de crontab van de gebruiker:

* * * * *   /usr/bin/env > /home/username/tmp/cron-env

nam het toen eruit nadat het bestand was geschreven.

Stap 2: Heb mezelf een beetje run-as-cron bash script gemaakt met:

#!/bin/bash
/usr/bin/env -i $(cat /home/username/tmp/cron-env) "$@"

Dus toen, als de gebruiker in kwestie, was ik in staat om

run-as-cron /the/problematic/script --with arguments --and parameters

Deze oplossing kan uiteraard worden uitgebreid om gebruik te maken van sudo of dergelijke voor meer flexibiliteit.

Ik hoop dat dit anderen helpt.


73
2017-11-18 14:40



Dit werkt niet voor mij en ik vraag me af of het voor iedereen die upmound doet. 1) Waarom gebruik je bash? Het is hier niet verplicht en bevindt zich mogelijk niet in /usr/bin. 2) Het cat …/cron-env voert meerdere regels uit, wat niet werkt. Probeer het gewoon uit te voeren /usr/bin/env -i $(cat cron-env) echo $PATH in de terminal voert het de omgeving letterlijk uit in plaats van het te gebruiken. 3) De huidige omgeving lekt in de geëmuleerde cron-omgeving. Proberen: export foo=leaked; run-as-cron echo $foo. - Marco
@Marco Werkt in bash, wat ik gebruik omdat het een beter gedefinieerde omgeving is dan sh. Ik gebruik alles, van pdksh, ksh (meerdere versies), bash en dash, dus ik ben me erg bewust van de verschillen tussen implementaties van "pure" of sh, zelfs als je heel strikt in de gemeenschappelijke subset van de talen blijft. :-) - Max Murphy
@Marco 2. cat voert meerdere regels uit, die wel werken, omdat shell substitutie ze samenvoegt tot een enkele regel, waarmee je kunt controleren echo $(cat cron-env ) | wc; uw voorbeeldopdracht, /usr/bin/env -i $(cat cron-env) echo $PATH, vervangers $PATH van de roepende schaal; in plaats daarvan moet het een subschaal aanroepen om te substitueren in het sub-milieu, b.v. /usr/bin/env -i $(cat cron-env) /bin/sh -c 'echo $PATH'. 3. Je hebt dezelfde fout gemaakt door opnieuw de schelp in plaats van in de subomgeving te vervangen - John Freeman


Ik presenteer een oplossing op basis van het antwoord van Pistos, maar zonder de gebreken.

  • Voeg de volgende regel toe aan de crontab, bijvoorbeeld gebruik makend van crontab -e

    * * * * *  /usr/bin/env > /home/username/cron-env
    
  • Maak een shellscript dat een opdracht in dezelfde omgeving uitvoert als cron-taken uitvoeren:

    #!/bin/sh
    
    . "$1"
    exec /usr/bin/env -i "$SHELL" -c ". $1; $2"
    

Gebruik:

run-as-cron <cron-environment> <command>

bijv.

run-as-cron /home/username/cron-env 'echo $PATH'

Merk op dat het tweede argument moet worden geciteerd als het een argument vereist. De eerste regel van het script laadt een POSIX-shell als interpreter. De tweede regel zoekt naar het cron-omgevingsbestand. Dit is vereist om de juiste shell te laden, die is opgeslagen in de omgevingsvariabele SHELL. Vervolgens laadt het een lege omgeving (om lekken van omgevingsvariabelen in de nieuwe schil te voorkomen), start dezelfde shell die wordt gebruikt voor cronjobs en laadt de cron-omgevingsvariabelen. Uiteindelijk wordt het commando uitgevoerd.


34
2017-09-24 18:46



dit heeft me geholpen mijn ruby-gerelateerde sphinx laadfout te reproduceren. - cweiske
Ik gebruikte de optie @reboot cron om het cron-env-bestand te schrijven. U kunt het dan in de crontab laten staan ​​en het zal alleen worden herschreven wanneer het systeem wordt gestart. Het maakt het een beetje eenvoudiger omdat je geen regels hoeft toe te voegen of te verwijderen. - Michael Barton


Omdat crontab het werk niet doet, moet je de inhoud manipuleren:

crontab -l | grep -v '^#' | cut -f 6- -d ' ' | while read CMD; do eval $CMD; done

Wat het doet :

  • vermeldt crontab-taken
  • verwijder commentaarregels
  • verwijder de crontab-configuratie
  • start ze dan een voor een op

14
2017-08-19 19:45



Dit doet het niet noodzakelijk in dezelfde omgeving als cron, en ik dacht dat hij er maar één wilde testen. - Falcon Momot
correct, ik heb me vergist ... Het loopt alleen de klusjes maar niet zoals cron zou doen! - Django Janny
nog steeds een geweldige oplossing +1 - Eric Uldall


Standaard met de meeste standaard cron-daemons die ik heb gezien, is er gewoon geen manier om cron te vertellen dat deze hier nu moet worden uitgevoerd. Als u anacron gebruikt, is het mogelijk dat ik denk dat ik een aparte instantie op de voorgrond moet uitvoeren.

Als uw scripts niet correct worden uitgevoerd, houdt u daar geen rekening mee

  • het script wordt uitgevoerd als een specifieke gebruiker
  • cron heeft een beperkte omgeving (de meest voor de hand liggende manifestatie hiervan is een ander pad).

Van crontab (5):

Verschillende omgevingsvariabelen zijn ingesteld   automatisch omhoog door de cron (8)   demon. SHELL is ingesteld op / bin / sh, en   LOGNAME en HOME worden ingesteld vanaf de   / etc / passwd-regel van de crontab's   eigenaar. PATH is ingesteld op "/ usr / bin: / bin".   HOME, SHELL en PATH kunnen dat zijn   overschreven door instellingen in de   crontab; LOGNAME is de gebruiker die de   taak loopt van, en misschien ook niet   veranderd.

Over het algemeen is PATH het grootste probleem, dus u moet:

  • Stel tijdens het testen de PATH expliciet in het script in op / usr / bin: / bin. Je kunt dit in bash doen met PATH exporteren = "/ usr / bin: / bin"
  • Stel expliciet het juiste pad in dat u wilt boven aan de crontab. bijv. PATH = "/ usr / bin: / bin: / usr / local / bin: / usr / sbin: / sbin"

Als u het script moet uitvoeren als een andere gebruiker zonder een shell (bijvoorbeeld www-data), gebruikt u sudo:

sudo -u www-data /path/to/crontab-script.sh

Het eerste dat je hiervoor moet testen, is natuurlijk dat je script daadwerkelijk doet wat het zou moeten doen vanaf de opdrachtregel. Als u het niet vanaf de opdrachtregel kunt uitvoeren, werkt het uiteraard niet met cron.


5
2017-11-18 14:27



Bedankt voor de grondige reactie. Ik ben me bewust van de twee problemen van hardlopen als een bepaalde gebruiker en met een bepaalde omgeving. Als zodanig heb ik mijn eigen antwoord geformuleerd, dat ik nu zal plaatsen ... - Pistos
Escape-tekens zijn een geldige reden waarom de taak niet wordt uitgevoerd - Joe Phillips


Nou, de gebruiker is dezelfde als degene die je in de crontab-invoer zet (of van wie je de crontab erin hebt gestopt, afwisselend), dus dat is een goed idee. crontab(5) zou je de lijst met omgevingsvariabelen moeten geven, er zijn er maar een paar.


1
2017-11-18 14:04



Met andere woorden, je zegt dat er geen manier is om het te doen? Alleen "genoeg" tijdelijke oplossingen? - Pistos
Nee, ik zeg dat u het kunt doen, met behulp van de informatie die ik in mijn antwoord heb verstrekt. - womble♦


In de meeste crontabs, zoals b.v. vixie-cron je kunt variabelen zo in de crontab zelf plaatsen en dan / usr / bin / env gebruiken om te controleren of het werkt. Op deze manier kun je je script in crontab laten werken als je eenmaal hebt ontdekt wat er mis is met het run-as-cron-script.

SHELL=/bin/bash
LANG=en
FASEL=BLA

* * * * *   /usr/bin/env > /home/username/cron-env

1
2017-10-27 06:52





Het script van Marco werkte om een ​​of andere reden niet voor mij. Ik had geen tijd om te debuggen, dus schreef ik een Python-script dat hetzelfde doet. Het is langer, maar: ten eerste werkt het voor mij, en ten tweede vind ik het gemakkelijker te begrijpen. Verander "/ tmp / cron-env" naar waar je je omgeving hebt opgeslagen. Hier is het:

#!/usr/bin/env python
from __future__ import division, print_function

import sys
import os

def main():
    if len(sys.argv) != 2 or sys.argv[1] in ('-h', '--help'):
        print("Usage: {} CMD\n"
              "Run a command as cron would. Note that CMD must be quoted to be only one argument."
              .format(sys.argv[0]))
        sys.exit(1)
    _me, cmd = sys.argv
    env = dict(line.strip().split('=', 1) for line in open('/tmp/cron-env'))
    sh = env['SHELL']
    os.execvpe(sh, [sh, '-c', cmd], env)

if __name__ == '__main__':
    main()

1
2017-12-24 08:48





De oplossing van Marco werkte niet voor mij, maar het pythonscript van Noam werkte. Hier is een kleine wijziging in het script van Marco waardoor het voor mij werkte:

#!/bin/sh
. "$1"
exec /usr/bin/env -i "$SHELL" -c "set -a;. $1; $2"

De toegevoegde set -a exporteer variabelen gedefinieerd in script $ 1 en maakte het beschikbaar om $ 2 te gebruiken

postscriptum De python van Noam werkte omdat het de omgeving 'exporteerde' naar het onderliggende proces.


1
2018-05-11 05:05





Ik heb nog nooit een manier gevonden om cron-taken handmatig uit te voeren, maar deze write-up suggereert het instellen van dezelfde omgeving als de cronjob zou hebben en het manueel uitvoeren van het script.


0
2017-11-18 14:07



Is het niet wat u voorstelt om te doen wat het OP wil weten? - womble♦
Dat is de reden waarom ik de link naar het artikel heb opgenomen waarin wordt beschreven hoe dit moet worden gedaan. Ik vond het niet nodig om alles hier te kopiëren en plakken. - oneodd1


je kunt de taak programmeren om de volgende minuut te beginnen :)


0
2017-09-23 13:52



59 seconden is veel tijd. - Stéphane Bruckert
Het OP noemde deze mogelijkheid in de vraag: "Is er een manier om dit te doen? 60 seconden wachten om veranderingen in het script te testen, is niet praktisch." - Andrew Grimm
59 seconden is waarschijnlijk minder dan het zou duren om een ​​van de andere voorgestelde (en niet gegarandeerd om te werken) oplossingen te kiezen en te implementeren. Wanneer ik dergelijke tekortkomingen zie, vraag ik me af hoe Linux zo'n de-facto standaard server-besturingssysteem werd. Zou een serieuze systeembeheerder zijn of haar baan niet willen testen? - Rolf