วิธีเรียกใช้คำสั่งเช่นเดียวกับในคิว


42

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

มีวิธีที่ฉันสามารถเรียกใช้คำสั่งเป็นคิวและเพิ่มคำสั่งให้กับคิวนั้นในขณะที่สิ่งต่าง ๆ กำลังทำงานอยู่หรือไม่?

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


3
ฉันขอแนะนำให้คุณยอมรับคำตอบที่ช่วยแก้ปัญหาของคุณได้ไหม ดูเหมือนว่ามีคนสองคนที่เหมาะกับคุณ
holmb

2
ใช่คุณอาจและฉันต้องการ ปัญหาคือฉันถามสิ่งนี้เมื่อฉันทำงานใน บริษัท ที่ใช้ Mac ฉันไม่ได้ทำงานที่นั่นอีกต่อไปและไม่มี Macs ด้วยตัวเองดังนั้นฉันจึงไม่มีวิธีการทดสอบสิ่งเหล่านี้ อย่ารู้สึกสะดวกสบายกับการทำเครื่องหมายว่าเป็นคำตอบเมื่อฉันไม่สามารถทดสอบได้ว่ามันใช้งานได้จริงดังนั้นตอนนี้ฉันหวังว่าผู้คนจะโหวตคำตอบเหล่านั้นที่พวกเขาพบว่าทำงานได้ดีสำหรับพวกเขาเพื่อให้ "คำตอบ" ปรากฏ แทน.
Svish

คำตอบ:


25

atยูทิลิตี้ที่รู้จักกันดีที่สุดสำหรับการใช้คำสั่งในเวลาที่กำหนดนอกจากนี้ยังมีคุณสมบัติคิวและสามารถขอให้เริ่มต้นการใช้คำสั่งในขณะนี้ มันอ่านคำสั่งเพื่อเรียกใช้จากอินพุตมาตรฐาน

echo 'command1 --option arg1 arg2' | at -q myqueue now
echo 'command2 ...' | at -q myqueue now

batchคำสั่งเทียบเท่ากับat -q b -m now( -mความหมายออกคำสั่งในกรณีใด ๆ จะถูกส่งไปยังคุณเช่น cron ไม่) ไม่ใช่ตัวแปร unix ทั้งหมดที่สนับสนุนชื่อคิว ( -q myqueue); คุณอาจถูก จำกัด bให้คิวเดียวที่เรียกว่า ลินุกซ์atถูก จำกัด ชื่อคิวตัวอักษรเดียว


2
บน linux เป็นอย่างน้อยดูเหมือนจะไม่รอให้คำสั่งก่อนหน้าเสร็จสิ้น
wds

@ wds ใช้งานได้สำหรับฉันใน Debian wheezy มันแตกได้ที่ไหนและอย่างไรสำหรับคุณ โปรดทราบว่าจะรอให้คำสั่งเสร็จสิ้นเท่านั้น หากคำสั่งเปิดใช้งานกระบวนการย่อยที่อยู่ได้นานกว่าแม่ของพวกเขาที่ไม่ต้องรอให้กระบวนการย่อย
Gilles 'ดังนั้นหยุดความชั่วร้าย'

ฉันลองใช้ CentOS 6 ฉันทดสอบด้วย "sleep x" ที่เรียบง่าย ฉันไม่แน่ใจว่าสิ่งที่จะทำงานนั้น แต่ฉันคิดว่ามันเริ่ม subshell และ subshell นั้นควรรอผล (การโทร sleep ไม่กลับมาทันที)
wds

เช่นเดียวกับชื่อคิว, 'ตอนนี้' ไม่ปรากฏมาตรฐานเช่นกัน: ทุบตีบนอูบุนตูกำลังบ่นเกี่ยวกับมัน ...
winwaed

@winwaed โอ้มันnowไม่ได้-t nowขอโทษ ฉันไม่ได้สังเกตว่าฉันทำผิดในรหัสตัวอย่าง
Gilles 'หยุดความชั่วร้าย'

23

ผนวก&ท้ายคำสั่งของคุณเพื่อส่งไปยังพื้นหลังและจากนั้นwaitมันก่อนที่จะเรียกใช้ต่อไป ตัวอย่างเช่น:

$ command1 &
$ wait; command2 &
$ wait; command3 &
$ ...

2
เย้! ไวยากรณ์นี้ยอดเยี่ยมมากเมื่อคุณเตะบางสิ่งออกไปจากนั้นไปดู stackoverflow เพื่อหาวิธีจัดคิวบางอย่างหลังจากนั้น
Erik Aronesty

2
หากคุณเปลี่ยนใจในคำสั่งใด ๆ เหล่านั้นในเวลาเดียวกันสิ่งที่สามารถทำได้เพื่อยกเลิกการwait? ดูเหมือนว่าไม่สามารถฆ่า killshot ของฉันทั้งหมดได้
Ken Williams

1
คุณเพิ่งฆ่าคำสั่ง waitเพียงแค่หยุดงานจนกว่าจะเสร็จสิ้นการคนก่อนหน้านี้
Gert Sønderby

มันจะใช้งานได้กับnohup?
Michael

11

คำตอบที่ดีของทั้ง Brad and Mankoff อีกอย่างที่คล้ายกับการรวมกันของทั้งคู่ก็คือการใช้หน้าจอ GNUเพื่อใช้คิวของคุณ นี่คือข้อดีของความสามารถในการทำงานในพื้นหลังคุณสามารถตรวจสอบได้ทุกเมื่อและจัดคิวคำสั่งใหม่เพียงแค่วางคำสั่งเหล่านั้นลงในบัฟเฟอร์ที่จะดำเนินการหลังจากที่คำสั่งก่อนหน้านี้ออกจาก

ก่อนอื่นให้เรียกใช้:

$ screen -d -m -S queue

(โดยบังเอิญตอนนี้เป็นเวลาที่ดีที่จะเล่นกับไฟล์ screenrc ที่ยอดเยี่ยม )

ที่จะวางไข่เซสชันหน้าจอพื้นหลังสำหรับคุณตั้งชื่อคิว

ตอนนี้จัดคิวคำสั่งได้มากเท่าที่คุณต้องการ:

screen -S queue -X stuff "echo first; sleep 4; echo second^M"

ฉันกำลังทำหลายคำสั่งด้านบนเพื่อทำการทดสอบ กรณีการใช้งานของคุณอาจดูเหมือน:

screen -S queue -X stuff "echo first^M"
screen -S queue -X stuff "echo second^M"

โปรดทราบว่า "^ M" ในบรรทัดของฉันด้านบนเป็นวิธีการขึ้นบรรทัดใหม่ที่ฝังซึ่งจะถูกตีความในภายหลังหลังจากที่หน้าจอยัดลงในเปลือกทุบตีที่มีอยู่ของคุณ ใช้ "CTL-V" เพื่อรับลำดับนั้น

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

screen -S queue -r

ในทางเทคนิคคุณไม่จำเป็นต้องตั้งชื่อเซสชันหน้าจอของคุณและมันจะทำงานได้ดี แต่เมื่อคุณติดมันคุณจะต้องปล่อยให้มันทำงานอยู่ตลอดเวลา ;-)

แน่นอนถ้าคุณทำเช่นนั้นวิธีที่ดีอีกวิธีหนึ่งก็คือตั้งชื่อ "คิว" ของหน้าต่างปัจจุบันและใช้:

screen -S queue -p queue -X stuff "command"

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

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

@ จอร์แดนดีมากมันใช้งานได้สำหรับฉัน แต่ "สิ่ง" สำหรับ after-X คืออะไร
Konstantin

@Konstantin gnu.org/software/screen/manual/html_node/Paste.html#Paste (TL; DR - สิ่งใดก็ตามที่เข้ามาในเทอร์มินัลราวกับว่าคุณพิมพ์)
Jordan

@ จอร์แดนฉันเห็นแล้วตอนนี้ มันเป็นคำสั่ง ฉันคิดว่ามันเป็นสตริงโดยพลการ
Konstantin

8

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

นี่คือสิ่งที่ฉันทำ

  1. ตั้งค่าเครื่องทั้งหมดที่เกี่ยวข้องกับการเชื่อมต่อเครือข่ายเพื่อให้สามารถเข้าถึงซึ่งกันและกัน

  2. บนเครื่องที่คุณย้ายไฟล์จาก (ต่อไปนี้เรียกว่าเครื่องต้นทาง) ให้ติดตั้ง rsync ด้วยapt-get install rsyncและTask Spoolerลับ(เว็บไซต์http://vicerveza.homeunix.net/~viric/soft/ts/ ) ถ้าคุณอยู่ใน Debian ชื่อแพ็กเกจสำหรับtsis task-spoolerและ executable ถูกเปลี่ยนชื่อเป็นtspเพื่อหลีกเลี่ยงการปะทะกันของชื่อด้วยtsexecutable จากmoreutilsแพ็คเกจ แพ็คเกจ Debian ที่เชื่อมโยงจากเว็บไซต์นั้นสามารถติดตั้งได้อย่างสมบูรณ์บน Ubuntu ด้วยdpkg -i task-spooler_0.7.3-1_amd64.debหรือคล้ายกัน

  3. apt-get install openssh-serverยังให้แน่ใจว่าทุกเครื่องมีการติดตั้งกับ SSH บนเครื่องต้นทางคุณต้องตั้งค่า SSH เพื่ออนุญาตการล็อกอินแบบไม่ใช้รหัสผ่านไปยังเครื่องเป้าหมาย วิธีที่จะใช้มากที่สุดคือการรับรองความถูกต้องของรหัสสาธารณะด้วยssh-agent(ดูhttps://www.google.se/search?q=ssh+public+key+authenticationสำหรับตัวอย่างของวิธีการนั้น) แต่บางครั้งฉันก็ใช้วิธีที่ง่ายขึ้น เช่นกันกับการตรวจสอบรหัสผ่าน เพิ่มสิ่งต่อไปนี้ในการกำหนดค่าไคลเอ็นต์ SSH ของคุณ (อย่างใดอย่างหนึ่ง~/.ssh/configหรือ/etc/ssh/ssh_config):

    Host *
         ControlMaster auto
         ControlPath ~/.ssh/master-%r@%h:%p
    

    จากนั้นเปิดเทอร์มินัลหนึ่งเครื่องบนเครื่องต้นทางเข้าสู่ระบบด้วยssh target1รับรองความถูกต้องตามปกติจากนั้นเปิดเทอร์มินัลนี้ ขอให้สังเกตว่ามีชื่อไฟล์ซ็อกเก็ต~/.ssh/master-user@target1:22ซึ่งเป็นไฟล์ที่จะเปิดใช้งานเซสชันต้นแบบที่ผ่านการตรวจสอบความถูกต้องและอนุญาตการเชื่อมต่อที่ไม่มีรหัสผ่านในภายหลังuser(ตราบใดที่การเชื่อมต่อใช้ชื่อโฮสต์และพอร์ตเป้าหมายเดียวกัน)

    ณ จุดนี้คุณต้องตรวจสอบว่าคุณสามารถเข้าสู่ระบบโดยไม่ได้รับแจ้งให้ตรวจสอบสิทธิ์ไปยังเครื่องเป้าหมาย

  4. ตอนนี้รันts rsync -ave ssh bigfile user@target1:ไฟล์เดียวหรือts rsync -ave ssh bigdir user@target1:สำหรับไดเรกทอรี ด้วย rsync สิ่งสำคัญคือไม่ต้องรวมเครื่องหมายสแลชต่อท้ายในไดเรกทอรี ( bigdirเทียบกับbigdir/) มิฉะนั้น rsync จะถือว่าคุณหมายถึงสิ่งที่เทียบเท่าbigdir/*ในเครื่องมืออื่น ๆ ส่วนใหญ่

    ตัวจัดคิวงานจะส่งคืนพรอมต์และให้คุณจัดคิวคำสั่งเหล่านี้จำนวนมากอย่างต่อเนื่อง ตรวจสอบคิวการรันด้วยtsโดยไม่มีอาร์กิวเมนต์

งานจัดคิวงานมีคุณสมบัติหลายอย่างเช่นการจัดเรียงคิววิ่งเรียกใช้งานที่เฉพาะเจาะจงเท่านั้นถ้างานอื่นวิ่งประสบความสำเร็จ ฯลฯ ts -hดูความช่วยเหลือด้วย ts -cบางครั้งผมออกคำสั่งตรวจสอบในขณะที่มีการทำงานกับ

มีวิธีอื่นในการทำเช่นนี้ แต่สำหรับกรณีการใช้งานของคุณพวกเขาทั้งหมดรวม Task Spooler ฉันเลือกที่จะใช้ rsync ผ่าน SSH เพื่อรักษาเวลาประทับไฟล์ซึ่งการคัดลอกผ่าน SMB จะไม่มี


ขอบคุณสำหรับคำตอบของคุณฉันไม่ทราบว่าtsมีประสิทธิภาพมากและใช้งานง่ายเพียงแค่แยก git บน autotoolized และ debianized
อเล็กซ์

@ อเล็กซ์ฉันได้ดูที่ส้อมของคุณและสนใจเป็นพิเศษในสิ่งที่ทำเกี่ยวกับการปรับค่าอัตโนมัติและการทำให้แหล่งที่มาเริ่มต้นซ้ำซ้อน คุณจะบังคับให้มีการผลักดันคอมมิทใหม่ซึ่งในขั้นตอนที่ 1 นำเข้าต้นฉบับและ 2. คอมมิชชันด้วยการเพิ่มของคุณ? มันจะช่วยให้บางคนเรียกดูแหล่งที่มาของคุณเพื่อ (เชื่อถือได้ง่ายขึ้น) เชื่อถือการเพิ่มของคุณไปยังแหล่งต้นฉบับ นี่เป็นหนึ่งในไม่กี่แพ็คเกจที่ฉันไม่ได้ติดตั้งจาก PPA หรือคล้ายกันดังนั้นมันจะดีถ้าคุณสร้างมันด้วยตัวเอง
holmb

คุณรู้ว่าฉันจะเปลี่ยนแว่นตาของฉันฉันสูญเสียส่วนหนึ่งของคำตอบของคุณเกี่ยวกับtask-spooler:-) ที่มีอยู่แล้ว ... อย่างไรก็ตามนั่นคือในความคิดเห็นของคุณเป็นคำแนะนำที่ดีมากฉันจะทำเร็ว ๆ นี้
อเล็กซ์

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

4

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

#!/usr/bin/perl

my $pid = shift;
die "Usage: $0 <pid> <command...>" unless $pid =~ /^\d+$/ && @ARGV;

print STDERR "Queueing process $$ after process $pid\n";
sleep 1 while -e "/proc/$pid";
exec @ARGV;

จากนั้นคุณเรียกใช้เช่น:

% command1 arg1 arg2 ...  # creates pid=2853
% after 2853 command2 arg1 arg2 ... # creates pid=9564
% after 9564 command3 arg1 arg2 ...

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


สคริปต์ที่ดี @ken แม้ว่าฉันจะแนะนำให้ลองใช้ตัวจัดคิวงานเนื่องจากคุณต้องการสิ่งนี้เป็นครั้งคราว ดูคำตอบของฉัน
holmb

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

จริง นั่นคือแง่มุมที่มีประโยชน์ของโซลูชันของคุณ
holmb

2

Command1 && Command2

  • "&&" หมายความว่า command2 จะทำงานหลังจาก command1 เสร็จสิ้นด้วยรหัสส่งคืนเป็น 0
  • หมายเหตุ: | | หมายความว่า command2 รันหลังจาก command1 เสร็จสิ้นพร้อมกับโค้ดส่งคืนอื่นที่ไม่ใช่ 0

1

คุณสามารถเพิ่มคำสั่งลงในบรรทัดคำสั่งของเชลล์ที่รันคำสั่งอยู่แล้ว

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

ตัวอย่างดังต่อไปนี้ คุณสามารถตัดและวางสิ่งของทั้งหมดหรือป้อนคำสั่งที่ตามมาในขณะที่ตัวที่ 1 กำลังทำงานอยู่ (ถ้าคุณพิมพ์เร็วมาก ๆ ) หรือมีโอกาสมากขึ้นในขณะที่ตัวที่สองกำลังทำงานอยู่:

echo "foo"
sleep 10; echo "bar"
sleep 3
echo "baz"

0

วิธีที่แฮ็กที่สุดที่ฉันคิดได้ก็คือรักษาคิว "สถานะ" ด้วยการล็อกไฟล์อย่างง่ายใน / tmp เมื่อ file1.sh กำลังทำคำสั่ง cp มันจะเก็บล็อกไฟล์ (หรือฮาร์ดลิงก์) ไว้ใน / tmp เมื่อเสร็จแล้วให้ลบไฟล์ สคริปต์อื่น ๆ ทุกตัวจะต้องค้นหา / tmp สำหรับล็อกไฟล์ด้วยรูปแบบการตั้งชื่อที่คุณเลือก ตามธรรมชาติแล้วสิ่งนี้อาจมีความล้มเหลวได้ทุกประเภท แต่มันเป็นเรื่องง่ายที่จะตั้งค่าและทำได้โดยสมบูรณ์ภายในการทุบตี


ยากที่จะใช้ในทางปฏิบัติเนื่องจากต้องการให้ทุกงานที่คุณต้องการเรียกใช้จำเป็นต้องได้รับการแก้ไขเพื่อเก็บไฟล์ล็อคและจำเป็นต้องรู้ (หรือยอมรับว่าเป็นพารามิเตอร์) ที่จะใช้ล็อคไฟล์ เมื่อใดก็ตามที่เป็นไปได้จะเป็นการดีที่สุดที่จะมีการจัดคิวจากภายนอกให้กับงาน
Ken Williams
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.