Linux: กำหนดการคำสั่งให้เรียกใช้หนึ่งครั้งหลังจากรีบูต (เทียบเท่า RunOnce)


26

ฉันต้องการกำหนดคำสั่งให้เรียกใช้หลังจากรีบูตในกล่อง Linux ฉันรู้วิธีการทำเช่นนี้เพื่อให้คำสั่งทำงานอย่างต่อเนื่องหลังจากรีบูตทุกครั้งด้วย@rebootรายการ crontab แต่ฉันต้องการให้คำสั่งรันเพียงครั้งเดียว หลังจากรันแล้วควรลบออกจากคิวคำสั่งเพื่อรัน ฉันกำลังมองหา Linux ที่เทียบเท่ากับRunOnceในโลกของ Windows

ในกรณีที่สำคัญ:

$ uname -a
Linux devbox 2.6.27.19-5-default #1 SMP 2009-02-28 04:40:21 +0100 x86_64 x86_64 x86_64 GNU/Linux
$ bash --version
GNU bash, version 3.2.48(1)-release (x86_64-suse-linux-gnu)
Copyright (C) 2007 Free Software Foundation, Inc.
$ cat /etc/SuSE-release
SUSE Linux Enterprise Server 11 (x86_64)
VERSION = 11
PATCHLEVEL = 0

มีวิธีที่ง่ายสคริปต์ในการทำเช่นนี้?


1
RunOnce เป็นสิ่งประดิษฐ์ของ Windows ที่เกิดจากปัญหาการกำหนดค่าให้เสร็จสิ้นก่อนที่จะรีบูต มีเหตุผลใดที่คุณไม่สามารถเรียกใช้สคริปต์ก่อนรีบูตได้หรือไม่ วิธีการแก้ปัญหาข้างต้นดูเหมือนจะเป็นโคลนที่เหมาะสมของ RunOnce
BillThor

คำตอบ:


38

สร้าง@rebootรายการใน crontab /usr/local/bin/runonceของคุณเพื่อเรียกใช้สคริปต์ที่เรียกว่า

สร้างโครงสร้างไดเรกทอรีที่เรียกว่าใช้/etc/local/runonce.d/ranmkdir -p

สร้างสคริปต์/usr/local/bin/runonceดังต่อไปนี้:

#!/bin/sh
for file in /etc/local/runonce.d/*
do
    if [ ! -f "$file" ]
    then
        continue
    fi
    "$file"
    mv "$file" "/etc/local/runonce.d/ran/$file.$(date +%Y%m%dT%H%M%S)"
    logger -t runonce -p local3.info "$file"
done

ตอนนี้วางสคริปต์ใด ๆ ที่คุณต้องการทำงานที่รีบูตถัดไป (เพียงครั้งเดียว) ในไดเรกทอรี/etc/local/runonce.dและchownและchmod +xได้อย่างเหมาะสม คุณจะพบว่ามันถูกย้ายไปยังranไดเรกทอรีย่อยและวันที่และเวลาที่ต่อท้ายชื่อ syslogนอกจากนี้ยังมีรายการในของคุณ


2
ขอบคุณสำหรับคำตอบ. วิธีนี้ดีมาก ในทางเทคนิคแก้ปัญหาของฉันได้อย่างไรก็ตามดูเหมือนว่ามีการเตรียมโครงสร้างพื้นฐานจำนวนมากที่จำเป็นสำหรับการทำงานนี้ มันไม่ได้พกพา ฉันคิดว่าโซลูชันของคุณจะถูกนำไปใช้ในการกระจาย Linux อย่างสมบูรณ์ (ฉันไม่แน่ใจว่าทำไมจึงไม่เป็นเช่นนั้น!) คำตอบของคุณเป็นแรงบันดาลใจทางออกสุดท้ายของฉันซึ่งฉันได้โพสต์เป็นคำตอบด้วย ขอบคุณอีกครั้ง!
Christopher Parker

อะไรที่ทำให้คุณเลือก local3 กับสิ่งอำนวยความสะดวกอื่น ๆ ระหว่าง 0 ถึง 7
Christopher Parker

3
@Christopher: การทอยลูกเต๋าเป็นวิธีที่ดีที่สุดเสมอ อย่างไรก็ตามอย่างจริงจังตัวอย่างเช่นมันไม่สำคัญและนั่นคือกุญแจสำคัญที่นิ้วของฉันลงจอด นอกจากนี้ฉันไม่ได้เป็นเจ้าของแปดเหลี่ยมตาย
หยุดชั่วคราวจนกว่าจะมีการแจ้งให้ทราบต่อไป

@Dennis: เข้าใจแล้วขอบคุณ บังเอิญ local3 man loggerสิ่งอำนวยความสะดวกในท้องถิ่นที่ปรากฏใน
Christopher Parker

ที่ไม่$fileตัวแปรประกอบด้วยเส้นทางแบบเต็มหรือเพียงแค่ชื่อไฟล์?
Andrew Savinykh

21

ผมขอขอบคุณที่ใส่ความพยายามในคำตอบที่เดนนิสวิลเลียมสัน ฉันต้องการยอมรับว่ามันเป็นคำตอบสำหรับคำถามนี้เนื่องจากมีความสวยงามและเรียบง่ายอย่างไรก็ตาม:

  • ในที่สุดฉันก็รู้สึกว่าต้องมีขั้นตอนมากเกินไปในการตั้งค่า
  • มันต้องมีการเข้าถึงรูต

ฉันคิดว่าวิธีแก้ปัญหาของเขาจะยอดเยี่ยมในฐานะที่เป็นคุณสมบัตินอกการจำหน่ายลินุกซ์

ที่ถูกกล่าวว่าฉันเขียนสคริปต์ของตัวเองเพื่อให้บรรลุสิ่งที่มากขึ้นหรือน้อยลงเช่นเดียวกับการแก้ปัญหาของเดนนิส มันไม่จำเป็นต้องมีขั้นตอนการตั้งค่าเพิ่มเติมและไม่จำเป็นต้องมีการเข้าถึงรูท

#!/bin/bash

if [[ $# -eq 0 ]]; then
    echo "Schedules a command to be run after the next reboot."
    echo "Usage: $(basename $0) <command>"
    echo "       $(basename $0) -p <path> <command>"
    echo "       $(basename $0) -r <command>"
else
    REMOVE=0
    COMMAND=${!#}
    SCRIPTPATH=$PATH

    while getopts ":r:p:" optionName; do
        case "$optionName" in
            r) REMOVE=1; COMMAND=$OPTARG;;
            p) SCRIPTPATH=$OPTARG;;
        esac
    done

    SCRIPT="${HOME}/.$(basename $0)_$(echo $COMMAND | sed 's/[^a-zA-Z0-9_]/_/g')"

    if [[ ! -f $SCRIPT ]]; then
        echo "PATH=$SCRIPTPATH" >> $SCRIPT
        echo "cd $(pwd)"        >> $SCRIPT
        echo "logger -t $(basename $0) -p local3.info \"COMMAND=$COMMAND ; USER=\$(whoami) ($(logname)) ; PWD=$(pwd) ; PATH=\$PATH\"" >> $SCRIPT
        echo "$COMMAND | logger -t $(basename $0) -p local3.info" >> $SCRIPT
        echo "$0 -r \"$(echo $COMMAND | sed 's/\"/\\\"/g')\""     >> $SCRIPT
        chmod +x $SCRIPT
    fi

    CRONTAB="${HOME}/.$(basename $0)_temp_crontab_$RANDOM"
    ENTRY="@reboot $SCRIPT"

    echo "$(crontab -l 2>/dev/null)" | grep -v "$ENTRY" | grep -v "^# DO NOT EDIT THIS FILE - edit the master and reinstall.$" | grep -v "^# ([^ ]* installed on [^)]*)$" | grep -v "^# (Cron version [^$]*\$[^$]*\$)$" > $CRONTAB

    if [[ $REMOVE -eq 0 ]]; then
        echo "$ENTRY" >> $CRONTAB
    fi

    crontab $CRONTAB
    rm $CRONTAB

    if [[ $REMOVE -ne 0 ]]; then
        rm $SCRIPT
    fi
fi

บันทึกสคริปต์นี้ (เช่นrunonce) chmod +xและการทำงาน:

$ runonce foo
$ runonce "echo \"I'm up. I swear I'll never email you again.\" | mail -s \"Server's Up\" $(whoami)"

ในกรณีที่พิมพ์ผิดคุณสามารถลบคำสั่งจากคิว runonce ด้วยแฟล็ก -r:

$ runonce fop
$ runonce -r fop
$ runonce foo

การใช้ sudo ทำงานตามที่คุณคาดหวัง มีประโยชน์สำหรับการเริ่มต้นเซิร์ฟเวอร์เพียงครั้งเดียวหลังจากรีบูตครั้งถัดไป

myuser@myhost:/home/myuser$ sudo runonce foo
myuser@myhost:/home/myuser$ sudo crontab -l
# DO NOT EDIT THIS FILE - edit the master and reinstall.
# (/root/.runonce_temp_crontab_10478 installed on Wed Jun  9 16:56:00 2010)
# (Cron version V5.0 -- $Id: crontab.c,v 1.12 2004/01/23 18:56:42 vixie Exp $)
@reboot /root/.runonce_foo
myuser@myhost:/home/myuser$ sudo cat /root/.runonce_foo
PATH=/usr/sbin:/bin:/usr/bin:/sbin
cd /home/myuser
foo
/home/myuser/bin/runonce -r "foo"

หมายเหตุบางส่วน:

  • สคริปต์นี้จำลองสภาพแวดล้อม (เส้นทาง, ไดเรกทอรีทำงาน, ผู้ใช้) ที่ถูกเรียกใช้
  • มันถูกออกแบบมาเพื่อชะลอการประมวลผลคำสั่งโดยทั่วไปเนื่องจากมันจะถูกดำเนินการ "ที่นี่ตอนนี้" จนกระทั่งหลังจากลำดับการบู๊ตครั้งถัดไป

สคริปต์ของคุณดูมีประโยชน์จริงๆ สิ่งหนึ่งที่ควรทราบคือมันทำลายความคิดเห็นออกจาก crontab
หยุดชั่วคราวจนกว่าจะมีการแจ้งให้ทราบต่อไป

@Dennis: ขอบคุณ ตอนแรกฉันไม่ได้มีการเรียก grep พิเศษ แต่มีความคิดเห็นทั้งหมดซ้อนกันอยู่ สามครั้งสำหรับทุกครั้งที่ฉันเรียกใช้สคริปต์ ฉันคิดว่าฉันจะเปลี่ยนสคริปต์เป็นเพียงลบบรรทัดความคิดเห็นที่ดูเหมือนความคิดเห็นที่สร้างขึ้นโดยอัตโนมัติสามข้อ
Christopher Parker

@Dennis: เสร็จแล้ว รูปแบบอาจจะดีกว่า แต่ใช้ได้สำหรับฉัน
Christopher Parker

@Dennis: จริง ๆ แล้วตาม crontab.c ฉันคิดว่ารูปแบบของฉันใช้ได้ดี (ค้นหา "อย่าแก้ไขไฟล์นี้" ที่opensource.apple.com/source/cron/cron-35/crontab/crontab.c. )
Christopher Parker

5

สร้างเช่น/root/runonce.sh:

#!/bin/bash
#your command here
sed -i '/runonce.sh/d' /etc/rc.local

เพิ่มไปที่/etc/rc.local:

/root/runonce.sh

นี่คืออัจฉริยะบริสุทธิ์ อย่าลืมที่จะ chmod + x theroot/runonce.sh นี่คือที่สมบูรณ์แบบสำหรับ apt-get อัพเกรดบนเครื่องสีฟ้าที่แขวนเพราะ walinuxagent บล็อก dpkg
CarComp

นี่มันแฮ็คเกินไป (แม้ว่ามันจะเป็นสิ่งที่ฉันคิดขึ้นตอนแรก)
iBug

2

ตั้งค่าสคริปต์ใน /etc/rc5.d ด้วย S99 และให้ลบตัวเองหลังจากรัน


2

คุณสามารถทำเช่นนี้กับatคำสั่ง แต่ผมสังเกตเห็นว่าคุณไม่สามารถ (อย่างน้อยใน RHEL 5 ซึ่งผมทดสอบบน) ใช้at @rebootหรือat rebootแต่คุณสามารถใช้แล้วat now + 2 minutesshutdown -r now

สิ่งนี้ไม่ต้องการให้ระบบของคุณใช้เวลานานกว่า 2 นาทีในการทำงาน

อาจเป็นประโยชน์เมื่อคุณต้องการตั้งค่า 0 ถึงแม้ว่าฉันต้องการให้คำสั่ง 'runonce' เป็นชุดมาตรฐาน


ระวังว่าหากระบบของคุณใช้เวลานานกว่า 2 นาทีจนกระทั่งatdหยุดคำสั่งของคุณอาจทำงานในระหว่างการปิดระบบ สิ่งนี้สามารถหลีกเลี่ยงได้โดยการหยุดatdก่อนกำหนดคำสั่งด้วยatd nowแล้วรีบูตเครื่อง
mleu

2

ฉันคิดว่าคำตอบนี้งดงามที่สุด:

วางสคริปต์ใน/etc/init.d/scriptและลบตัวเองด้วยบรรทัดสุดท้าย:rm $0

เว้นแต่ว่าสคริปต์นั้นสามารถป้องกันข้อผิดพลาดได้ 100% คุณควรจัดการกับข้อยกเว้นเพื่อหลีกเลี่ยงการเกิดข้อผิดพลาดร้ายแรง


2

ฉันเคยchkconfigให้ระบบของฉันเรียกใช้สคริปต์โดยอัตโนมัติหนึ่งครั้งหลังจากบูตและไม่เคยอีกครั้ง หากระบบของคุณใช้ ckconfig (Fedora, RedHat, CentOs ฯลฯ ) สิ่งนี้จะใช้ได้

ก่อนอื่นสคริปต์:

#!/bin/bash
# chkconfig: 345 99 10
# description: This script is designed to run once and then never again.
#


##
# Beginning of your custom one-time commands
#

plymouth-set-default-theme charge -R
dracut -f

#
# End of your custom one-time commands
##


##
# This script will run once
# If you would like to run it again.  run 'chkconfig run-once on' then reboot.
#
chkconfig run-once off
chkconfig --del run-once
  1. ตั้งชื่อสคริปต์ run-once
  2. วางสคริปต์ใน /etc/init.d/
  3. เปิดใช้งานสคริปต์ chkconfig run-once on
  4. รีบูต

เมื่อบูทระบบสคริปต์ของคุณจะทำงานอีกครั้งและไม่เคยอีกครั้ง

นั่นคือไม่ต้องทำอีกเว้นแต่คุณต้องการ คุณสามารถเปิดใช้งานสคริปต์อีกครั้งด้วยchkconfig run-once onคำสั่ง

ฉันชอบโซลูชันนี้เพราะมันทำให้ไฟล์หนึ่งไฟล์มีเพียงไฟล์เดียวในระบบและเพราะคำสั่งที่เรียกใช้ครั้งเดียวสามารถออกใหม่ได้หากจำเป็น


-1

ในระบบ redhat และ debian คุณสามารถทำได้จาก /etc/rc.local มันเป็น autoexec.bat ชนิดหนึ่ง


7
นั่นจะได้รับการดำเนินการในการบู๊ตแต่ละครั้ง
หยุดชั่วคราวจนกว่าจะมีการแจ้งให้ทราบต่อไป

1
ไม่ดีของฉันฉันผิดคำถาม ขอบคุณสำหรับการแก้ไข
natxo asenjo
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.