मैन्युअल रूप से और तुरंत एक क्रोन नौकरी चलाना


108

(मैंने पहले ही पढ़ा है कि मैं एक नई क्रोन स्क्रिप्ट का परीक्षण कैसे कर सकता हूं? )

मेरे पास एक विशिष्ट समस्या है (क्रॉन जॉब दौड़ना, या ठीक से चलाना प्रकट नहीं होता है), लेकिन समस्या सामान्य है: मैं उन स्क्रिप्ट्स को डीबग करना चाहूंगा जो क्रोन किए गए हैं। मुझे पता है कि मैं एक * * * * क्रॉस्टैब लाइन सेट कर सकता हूं, लेकिन यह पूरी तरह से संतोषजनक समाधान नहीं है। मैं कमांड लाइन से क्रोन की नौकरी चलाने में सक्षम होना चाहूंगा जैसे कि क्रॉन इसे चला रहे थे (एक ही उपयोगकर्ता, एक ही पर्यावरण चर, आदि)। क्या इसे करने का कोई तरीका है? स्क्रिप्ट परिवर्तनों का परीक्षण करने के लिए 60 सेकंड इंतजार करना व्यावहारिक नहीं है।


(क्षमा करें टिप्पणी नहीं जोड़ सकते) 0 30 16 20 *? * यहां तक ​​कि अगर आप उस तरह से नौकरी चलाते हैं, तो पूरा विचार यह है कि स्क्रिप्ट आउटपुट प्रदान करने के लिए यह देखने के लिए कि क्या गलत हो रहा है जब तक कि नौकरी एक लॉग को नहीं लिखती है, यह बेकार है

जवाबों:


80

यहाँ मैंने क्या किया है, और यह इस स्थिति में काम करता है। कम से कम, यह मुझे एक त्रुटि दिखाता है, जबकि कमांड लाइन से चल रहा है क्योंकि उपयोगकर्ता त्रुटि नहीं दिखाता है।


चरण 1 : मैंने इस लाइन को अस्थायी रूप से उपयोगकर्ता के क्रैस्टैब में रखा:

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

फ़ाइल लिखे जाने के बाद फिर उसे निकाल लिया।

चरण 2 : खुद को थोड़ा रन-ए-क्रॉन बैश स्क्रिप्ट से युक्त करें:

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

तो, सवाल में उपयोगकर्ता के रूप में, मैं करने में सक्षम था

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

इस समाधान को स्पष्ट रूप से सूडो या अधिक लचीलेपन के लिए उपयोग करने के लिए विस्तारित किया जा सकता है।

आशा है कि यह दूसरों की मदद करता है।


8
यह मेरे लिए काम नहीं करता है और मुझे आश्चर्य है कि अगर यह किसी के लिए भी करता है जो उत्थान करता है। 1) आप बैश का उपयोग क्यों कर रहे हैं? यहां इसकी आवश्यकता नहीं है और यह इसमें स्थित नहीं हो सकता है /usr/bin। 2) cat …/cron-envआउटपुट कई लाइनों, जो काम नहीं करता है। बस /usr/bin/env -i $(cat cron-env) echo $PATHटर्मिनल में निष्पादित करने का प्रयास करें , यह पर्यावरण का उपयोग करने के बजाय शाब्दिक रूप से आउटपुट करता है। 3) वर्तमान वातावरण उत्सर्जित क्रोन वातावरण में लीक हो जाता है। प्रयास करें: export foo=leaked; run-as-cron echo $foo
मार्को

@ मार्को बाश में काम करता है, जो कि मैं उपयोग करता हूं क्योंकि यह श की तुलना में बेहतर परिभाषित वातावरण है। मैं pdksh, ksh (कई संस्करण), बैश और डैश से सब कुछ का उपयोग करता हूं, इसलिए मैं "शुद्ध" श के कार्यान्वयन के बीच अंतरों के बारे में बहुत जागरूक हूं, यहां तक ​​कि भाषाओं के सामान्य सबसेट में बहुत सख्ती से रहने पर भी। :-)
मैक्स मर्फी

7
@ मार्को 2. catकई लाइनों को आउटपुट करता है, जो काम करते हैं, क्योंकि शेल प्रतिस्थापन उन्हें एक ही लाइन में ढहता है, जिसे आप जांच सकते हैं echo $(cat cron-env ) | wc; आपका उदाहरण कमांड, कॉलिंग शेल से /usr/bin/env -i $(cat cron-env) echo $PATHस्थानापन्न $PATH; इसके बजाय, यह सबवेनिरोनमेंट में स्थानापन्न करने के लिए एक उपखंड को आमंत्रित करना चाहिए, जैसे /usr/bin/env -i $(cat cron-env) /bin/sh -c 'echo $PATH'। 3. आपने एक ही गलती की है, फिर से उप
जॉन फ्रीमैन

41

मैं पिस्तोस उत्तर के आधार पर एक समाधान प्रस्तुत करता हूं, लेकिन खामियों के बिना।

  • निम्न लाइन को क्रासटैब में जोड़ें, उदाहरण के लिए crontab -e

    * * * * *  /usr/bin/env > /home/username/cron-env
    
  • एक शेल स्क्रिप्ट बनाएं जो क्रोन जॉब्स चलाने के समान वातावरण में एक कमांड निष्पादित करता है:

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

उपयोग:

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

जैसे

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

ध्यान दें कि एक तर्क की आवश्यकता होने पर दूसरे तर्क को उद्धृत किया जाना चाहिए। स्क्रिप्ट की पहली पंक्ति दुभाषिया के रूप में एक पोसिक्स शेल को लोड करती है। दूसरी पंक्ति क्रोन पर्यावरण फ़ाइल का स्रोत है। यह सही शेल को लोड करने के लिए आवश्यक है, जो पर्यावरण चर में संग्रहीत है SHELL। फिर यह एक खाली वातावरण (नए शेल में पर्यावरण चर के रिसाव को रोकने के लिए) को लोड करता है, उसी शेल को लॉन्च करता है जो क्रोनोजर के लिए उपयोग किया जाता है और क्रोन पर्यावरण चर को लोड करता है। अंत में कमांड को निष्पादित किया जाता है।


इससे मुझे अपने रूबी-संबंधित स्फिंक्स लोडिंग त्रुटि को पुन: उत्पन्न करने में मदद मिली।
cweiske

1
मैंने cron-env फाइल लिखने के लिए @reboot cron विकल्प का उपयोग किया। फिर आप इसे क्रॉस्टैब में छोड़ सकते हैं और यह केवल फिर से लिखा जाएगा जब सिस्टम शुरू हो जाएगा। यह थोड़ा सरल बनाता है क्योंकि आपको लाइनों को जोड़ने / निकालने की आवश्यकता नहीं है।
माइकल बार्टन

हां, पिस्टोस समाधान मेरे लिए काम नहीं करता था लेकिन इसने किया
स्टैक

19

Crontab के रूप में काम नहीं करते हैं, आप इसे सामग्री में हेरफेर करने के लिए है:

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

यह क्या करता है :

  • Crontab नौकरियों की सूची
  • टिप्पणी लाइनों को हटा दें
  • Crontab विन्यास को हटा दें
  • फिर उन्हें एक-एक करके लॉन्च करें

5
यह जरूरी नहीं कि यह उसी माहौल में हो, जो क्रोन करेगा, हालांकि, और मुझे लगा कि वह उनमें से केवल एक का परीक्षण करना चाहता था।
फाल्कन मोमोट

2
सही है, मुझसे गलती हुई है ... यह केवल नौकरियां चलाता है लेकिन क्रॉन की तरह नहीं होगा!
19ango में Django Janny

5
अभी भी एक भयानक समाधान +1
एरिक उलल्ड

1
आप बस sudo -H -u otheruser bash -c 'crontab..." दूसरे उपयोगकर्ता btw के crontab को चलाने के लिए कर सकते हैं
फ्रीडो

5

सबसे डिफ़ॉल्ट क्रोन डेमॉन के साथ डिफ़ॉल्ट रूप से जो मैंने देखा है, अभी क्रोन को यहीं चलाने के लिए कहने का कोई तरीका नहीं है। यदि आप एनाक्रॉन का उपयोग कर रहे हैं, तो यह संभव हो सकता है कि मैं अग्रभूमि में एक अलग उदाहरण चलाना चाहता हूं।

यदि आपकी स्क्रिप्ट ठीक से नहीं चल रही हैं तो आप उस पर ध्यान नहीं दे रहे हैं

  • स्क्रिप्ट एक विशेष उपयोगकर्ता के रूप में चल रही है
  • क्रोन में एक प्रतिबंधित वातावरण है (इसका सबसे स्पष्ट प्रकटीकरण एक अलग रास्ता है)।

Crontab से (5):

कई पर्यावरण चर स्वचालित रूप से क्रोन (8) डेमन द्वारा स्थापित किए जाते हैं। शेल / बिन / श के लिए सेट किया गया है, और LOGNAME और HOME को crontab के मालिक के / etc / passwd लाइन से सेट किया गया है। PATH "/ usr / bin: / bin" पर सेट है। कंट्रास्ट में सेटिंग्स द्वारा होम, शेल और पैट को ओवरराइड किया जा सकता है; LOGNAME वह उपयोगकर्ता है जो नौकरी से भाग रहा है, और उसे बदला नहीं जा सकता है।

सामान्य तौर पर PATH सबसे बड़ी समस्या है, इसलिए आपको निम्न करने की आवश्यकता है:

  • पटकथा को / usr / bin: / bin पर परीक्षण करते समय, स्क्रिप्ट के भीतर स्पष्ट रूप से सेट करें। आप इसे निर्यात पेट के साथ बैश में कर सकते हैं = "/ usr / bin: / bin"
  • स्पष्ट रूप से उचित पठार सेट करें जिसे आप क्रॉस्टैब के शीर्ष पर चाहते हैं। जैसे PATH = "/ usr / bin: / bin: / usr / local / bin: / usr / sbin:" sbin "

यदि आपको शेल के बिना किसी अन्य उपयोगकर्ता के रूप में स्क्रिप्ट को चलाने की आवश्यकता है (उदाहरण के लिए www-डेटा), तो sudo का उपयोग करें:

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

उन सभी से पहले परीक्षण करने के लिए पहली बात, ज़ाहिर है, आपकी स्क्रिप्ट वास्तव में वही करती है जो कमांड लाइन से करना चाहिए। यदि आप इसे कमांड लाइन से नहीं चला सकते हैं, तो यह स्पष्ट रूप से क्रोन से काम नहीं करेगा।


पूरी प्रतिक्रिया के लिए धन्यवाद। मैं एक विशेष उपयोगकर्ता के रूप में और एक विशेष वातावरण के साथ चलने के दो मुद्दों से अवगत हूं। जैसे, मैंने अपना जवाब तैयार किया है, जिसे अब मैं पोस्ट
करूंगा

भागने के पात्र नौकरी नहीं चलने के एक वैध कारण हैं
जो फिलिप्स

2

मार्को की स्क्रिप्ट मेरे लिए किसी कारण से काम नहीं आई। मेरे पास डीबग करने का समय नहीं था, इसलिए मैंने एक पायथन स्क्रिप्ट लिखी जो कि समान काम करती है। यह लंबा है, लेकिन: पहला, यह मेरे लिए काम करता है, और दूसरा, मुझे यह समझना आसान लगता है। "/ Tmp / cron-env" बदलें जहाँ आपने अपना पर्यावरण बचाया है। यह रहा:

#!/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

ठीक है, उपयोगकर्ता वही है जो आप कॉन्टैब प्रविष्टि (या जिसका क्रैस्टब आप इसे डालते हैं, वैकल्पिक रूप से) में डालते हैं, इसलिए यह एक नो-ब्रेनर है। crontab(5) आपको पर्यावरण चर की सूची सेट करनी चाहिए, केवल कुछ ही है।


दूसरे शब्दों में, आप कह रहे हैं कि ऐसा करने का कोई तरीका नहीं है? केवल "करीब पर्याप्त" workarounds?
पिस्तोस

नहीं, मैं कह रहा हूं कि आप मेरे उत्तर में दी गई जानकारी का उपयोग करके ऐसा कर सकते हैं।
Womble

1

उदाहरणार्थ विक्सी-क्रॉन जैसे अधिकांश क्रॉस्टैब्स में आप इस तरह से क्रॉस्टैब में वैरिएबल रख सकते हैं और फिर काम करने के लिए / usr / bin / env का उपयोग कर सकते हैं। इस तरह से आप रन-ए-क्रॉन स्क्रिप्ट में गलत होने के बारे में पता लगाने के बाद अपने स्क्रिप्ट को क्रॉस्टैब में काम कर सकते हैं।

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

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

1

मार्को का समाधान मेरे लिए काम नहीं आया लेकिन नोआम की अजगर स्क्रिप्ट ने काम किया। यहाँ मार्को की पटकथा में थोड़ा संशोधन किया गया है जिससे यह मेरे काम आया:

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

जोड़ा set -aनिर्यात चर स्क्रिप्ट $ 1 में परिभाषित किया गया है और इसे $ 2 को कमांड करने के लिए उपलब्ध कराया गया है

पीएस नोआम के अजगर ने काम किया क्योंकि यह बच्चे की प्रक्रिया के लिए 'निर्यात' पर्यावरण था।


1

यदि यह एक शेल स्क्रिप्ट है, तो यह आपको अधिकांश तरीके से मिलनी चाहिए:

sudo su  # (assuming it's run as root, if not switch to the user you want it to run as)
cd  # Switch to home folder
sh <full-path/my-shell-script>

यह निश्चित रूप से कुछ समस्याओं को उजागर करेगा, अगर सब कुछ नहीं।


0

मैंने कभी भी क्रोन जॉब्स को मैन्युअल रूप से चलाने का एक तरीका नहीं पाया है, लेकिन यह लिखने का तरीका बताता है कि क्रोनजोब के पास एक ही वातावरण होगा और स्क्रिप्ट को मैन्युअल रूप से चलाना होगा।


क्या आप ऐसा नहीं करने का सुझाव देते हैं जो ओपी जानना चाहता है कि कैसे करना है?
Womble

यही कारण है कि मैंने राइट-अप के लिंक को शामिल किया है जो बताता है कि यह कैसे करना है। मैंने यहां सब कुछ कॉपी-पेस्ट करना जरूरी नहीं समझा।
वनोड्ड 1

0

आप अगले मिनट शुरू करने के लिए नौकरी कार्यक्रम कर सकते हैं :)


7
59 सेकंड बहुत समय है।
स्टेफेन ब्रुकर्ट

ओपी ने प्रश्न में इस संभावना का उल्लेख किया: "क्या ऐसा करने का कोई तरीका है? स्क्रिप्ट परिवर्तनों का परीक्षण करने के लिए 60 सेकंड प्रतीक्षा करने के लिए व्यावहारिक नहीं है।"
एंड्रयू ग्रिम

59 सेकंड संभवत: इससे कम है कि किसी अन्य प्रस्तावित (और काम की गारंटी नहीं) समाधानों को लेने और लागू करने के लिए ले जाएगा। जब मैं ऐसी कमियों को देखता हूं तो मुझे आश्चर्य होता है कि लिनक्स इस तरह का वास्तविक मानक सर्वर ओएस कैसे बन गया। किसी भी गंभीर sysadmin अपनी नौकरी का परीक्षण नहीं करना चाहते हैं?
रॉल्फ

0

मैंने मार्को के जवाब पर भरोसा किया। कोड नीचे दिखाया गया है, लेकिन मैं इस स्क्रिप्ट को यहां रखूंगा ।

इस crontab को देखते हुए:

# m h  dom mon dow   command

X=Y
1 2 3 4 5 6 echo "Hello, world"
1 2 3 4 5 6 echo "Goodby, cruel world"
1 2 3 4 5 6 echo "Please spare me the drama"

नमूना उपयोग सत्र:

$ cronTest
This is the crontab for  without comment lines or blank lines:
     1  X=Y
     2  echo "Hello, world"
     3  echo "Goodby, cruel world"
     4  echo "Please spare me the drama"
Which line would you like to run as  now?
55
55 is not valid, please enter an integer from 1 to 4
2

Evaluating 1: X=Y

Evaluating 2: echo "Hello, world"
Hello, world

यह वह है cronTest2, जिसे पर्यावरण चर को ठीक उसी तरह लागू करने की आवश्यकता है , जिस तरह से क्रोन करता है:

#!/bin/bash

# Prompt user for a user crontab entry to execute

function deleteTempFile {
  rm -f $TEMP_FILE
}

function debug {
  if [ "$DEBUG" ]; then >&2 printf "$1\n"; fi
}

function isValidLineNumber {
  # $1 - number of lines
  # $2 - requested line number
  if [[ -n "${2//[0-9]+/}" ]] && (( $2 <= $1 )); then echo true; else echo false; fi
}

function isVariableAssignment {
  [[ "$( echo "$1" | grep "=" )" ]]
}

function makeTempCrontab {
  local -r ASTERISK=\\*
  local -r NUMBER='[[:digit:]]{1,2}'
  local -r NUMBERS="$NUMBER(,$NUMBER)+"
  local -r CRON="^(($ASTERISK|$NUMBER|$NUMBERS)[[:space:]]+)"
  local -r CRON5_REGEX="$CRON{5}"
  local -r CRON6_REGEX="$CRON{6}"

  rm -f "$TEMP_FILE"

  local -r ALL_LINES="$( crontab -l )"

  # Ignore empty lines and lines starting with # (comment lines)
  local -r LINES="$( 
    echo "$ALL_LINES" | \
    grep -v '^[[:space:]]*#' | \
    grep -v '^[[:space:]]*$'
  )"

  if [[ -z "$LINES" ]]; then
    echo "Your crontab is empty, nothing to do"
    exit 1
  fi

  IFS=$'\n' 
  for LINE in $LINES; do
    LINE="$( echo "$LINE" | sed 's/\s\+$//e' )" # remove trailing space
    if [ "$( echo "$LINE" | grep "^$" )" ]; then  
      debug ""  # ignore empty line
    elif [ "$( echo "$LINE" | egrep "$CRON6_REGEX" )" ]; then
      debug "6 field date/time specifier: $LINE"
      # strip out when to run debug, leaving just the command to execute
      echo "$LINE" | cut -f 7- -d ' ' >> "$TEMP_FILE"
    elif [ "$( echo "$LINE" | egrep "$CRON5_REGEX" )" ]; then
      debug "5 field date/time specifier: $LINE"
      # strip out when to run debug, leaving just the command to execute
      echo "$LINE" | cut -f 6- -d ' ' >> "$TEMP_FILE"
    elif [ "$( echo "$LINE" | grep '^@' )" ]; then
      debug "@declaration: $LINE"
      # strip out @declaration, leaving just the command to execute
      echo "$LINE" | cut -f 2- -d ' ' >> "$TEMP_FILE"
    elif [ "$( echo "$LINE" | grep '=' )" ]; then
      debug "Variable assignment: $LINE"
      echo "$LINE"  >> "$TEMP_FILE"
    else
      debug "Ignored: $LINE"
    fi
  done
  unset IFS
}

function runUpToLine {
  # Scans up to given line number in $TEMP_FILE
  # Evaluates variable assignment
  # Executes specified line
  # Ignores remainder of file
  # Function definitions are not supported
  #
  # $1 - line number to run

  readarray CONTENTS < "$TEMP_FILE"
  for (( i=0; i<=$1; i++ )); do
    # >&2 echo "\$i=$i, \$1=$1, isVariableAssignment: $( isVariableAssignment $CONTENTS[$i] ), CONTENTS[$i]=${CONTENTS[$i]}"
    if isVariableAssignment ${CONTENTS[$i]} || (( $i == $1 )); then
      printf "\nEvaluating $(( i+1 )): ${CONTENTS[$i]}"
      eval "${CONTENTS[$i]}"
    fi
  done
}

function selectLine {
  >&2 echo "This is the crontab for $USER without comment lines or blank lines:"
  cat -n "$TEMP_FILE" >&2
  >&2 echo "Which line would you like to run as $USER now?"

  local -r NUM_LINES=$( cat "$TEMP_FILE" | wc -l )
  read LINE_NUMBER
  # >&2 echo "NUM_LINES=$NUM_LINES, LINE_NUMBER=$LINE_NUMBER;  valid: $( isValidLineNumber $NUM_LINES $LINE_NUMBER )"
  while [[ $( isValidLineNumber $NUM_LINES $LINE_NUMBER ) == false ]]; do
    >&2 echo "$LINE_NUMBER is not valid, please enter an integer from 1 to $NUM_LINES"
    read LINE_NUMBER
    # >&2 echo "NUM_LINES=$NUM_LINES, LINE_NUMBER=$LINE_NUMBER;  valid: $( isValidLineNumber $NUM_LINES $LINE_NUMBER )"
  done
  (( LINE_NUMBER-- ))
  echo ${LINE_NUMBER}
}

function doIt {
  export USER=$1
  local -r TEMP_FILE="$( mktemp crontabTest.XXX )"
  trap deleteTempFile EXIT

  makeTempCrontab
  local -r LINE_NUMBER="$( selectLine )"
  runUpToLine $LINE_NUMBER
}

doIt "$1" 

cronTestcronTest2समुचित वातावरण चर के साथ चलाता है :

#!/bin/bash

# Execute a user crontab entry with the proper environment

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"

env -i bash --noprofile --norc -c "$DIR/cronTest2 $USER"
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.