Cara menjalankan perintah seperti dalam antrian

42

Saya perlu banyak menyalin berbagai file ke berbagai folder. Saya dapat menambahkan semua perintah salin saya ke skrip bash dan kemudian menjalankannya, tetapi kemudian saya harus menunggu sampai selesai jika saya ingin menambahkan lebih banyak perintah ke "antrian" penyalinan itu.

Apakah ada cara saya bisa menjalankan perintah sebagai antrian dan semacam menambahkan lebih banyak perintah ke antrian itu sementara semuanya berjalan?

Dijelaskan dengan cara yang berbeda, saya ingin memulai tugas yang berjalan lama. Sementara itu sedang berjalan saya ingin memulai yang lain yang tidak benar-benar mulai sampai yang pertama selesai. Dan kemudian tambahkan yang lain setelah yang terakhir dan seterusnya. Apakah ini mungkin?

Svish
sumber
3
Izinkan saya menyarankan Anda menerima jawaban yang memecahkan masalah Anda. Tampaknya ada beberapa dari mereka yang akan bekerja untuk Anda.
holmb
2
Ya, mungkin, dan saya menginginkannya. Masalahnya adalah saya menanyakan ini ketika saya bekerja di perusahaan yang menggunakan Mac. Saya tidak lagi bekerja di sana, saya juga tidak punya Mac jadi saya tidak punya cara untuk menguji semua ini. Jangan merasa nyaman dengan menandai satu sebagai jawaban ketika saya tidak dapat menguji apakah itu benar-benar berfungsi, jadi untuk saat ini saya berharap orang-orang memilih jawaban yang menurut mereka cocok untuk mereka sehingga "jawaban" dapat muncul dengan cara itu sebagai gantinya.
Svish

Jawaban:

25

The atutilitas, paling dikenal untuk menjalankan perintah pada waktu tertentu, juga memiliki fitur antrian dan dapat diminta untuk mulai menjalankan perintah sekarang. Bunyinya perintah untuk menjalankan dari input standar.

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

The batchperintah setara dengan at -q b -m now( -myang berarti output perintah, jika ada, akan dikirimkan kepada Anda, seperti cron tidak). Tidak semua varian unix mendukung nama antrian ( -q myqueue); Anda mungkin terbatas pada satu antrian yang dipanggil b. Linux atterbatas pada nama antrian huruf tunggal.

Gilles 'SANGAT berhenti menjadi jahat'
sumber
2
Di linux setidaknya ini sepertinya tidak menunggu perintah sebelumnya selesai.
wds
@wds Bekerja untuk saya di Debian wheezy. Di mana dan bagaimana hal itu pecah untuk Anda? Perhatikan bahwa hanya menunggu perintah selesai; jika perintah meluncurkan subproses yang hidup lebih lama dari induknya, at tidak menunggu subproses.
Gilles 'SANGAT berhenti menjadi jahat'
Saya mencoba pada CentOS 6. Saya diuji hanya dengan "sleep x" sederhana. Saya tidak yakin apa yang harus dilakukan untuk menjalankan itu, tetapi saya menganggapnya memulai subkulit dan bahwa subkulit harus menunggu hasilnya (panggilan tidur tidak segera kembali).
wds
Seperti halnya nama antrian, 'sekarang' juga tidak muncul standar: bash di ubuntu mengeluh tentang hal itu ...
winwaed
@ dinanti Oh, nowtidak -t now, maaf. Saya tidak memperhatikan bahwa saya salah dalam kode sampel.
Gilles 'SANGAT berhenti menjadi jahat'
23

Tambahkan &ke akhir perintah Anda untuk mengirimnya ke latar belakang, dan kemudian waitdi atasnya sebelum menjalankan berikutnya. Sebagai contoh:

$ command1 &
$ wait; command2 &
$ wait; command3 &
$ ...
Vortico
sumber
2
yay! sintaks ini luar biasa ketika Anda telah menendang sesuatu dan kemudian pergi melihat stackoverflow untuk cara mengantri sesuatu setelah itu
Erik Aronesty
2
Jika Anda berubah pikiran pada salah satu perintah itu sementara itu, apa yang dapat dilakukan untuk membatalkan wait? Tampaknya tahan terhadap semua pembunuhan saya.
Ken Williams
1
Anda baru saja membunuh perintah. The waithanya berhenti pekerjaan sampai yang sebelumnya selesai.
Gert Sønderby
Apakah ini akan berhasil nohup?
Michael
11

Solusi Brad dan Mankoff adalah saran yang bagus. Yang lain yang mirip dengan kombinasi keduanya adalah dengan menggunakan Layar GNU untuk mengimplementasikan antrian Anda. Ini memiliki keuntungan karena dapat dijalankan di latar belakang, Anda dapat memeriksanya kapan saja, dan mengantre perintah baru hanya menempelkannya ke buffer yang akan dieksekusi setelah perintah sebelumnya keluar.

Lari pertama:

$ screen -d -m -S queue

(kebetulan, sekarang adalah waktu yang tepat untuk bermain dengan beberapa file screenrc . )

Itu akan memunculkan sesi layar latar belakang untuk Anda bernama antrian.

Sekarang, antreikan sebanyak mungkin perintah yang Anda suka:

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

Saya melakukan beberapa perintah di atas hanya untuk pengujian. Kasing penggunaan Anda mungkin akan lebih mirip:

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

Perhatikan bahwa "^ M" pada baris saya di atas adalah cara untuk mendapatkan baris baru tertanam yang akan ditafsirkan nanti setelah layar memasukkannya ke dalam bash shell yang ada. Gunakan "CTL-V," untuk mendapatkan urutan itu.

Akan sangat mudah untuk membuat beberapa shell-script sederhana untuk mengotomatiskannya dan mengantri perintah. Kemudian, setiap kali Anda ingin memeriksa status antrian latar belakang Anda, Anda lampirkan kembali melalui:

screen -S queue -r

Secara teknis, Anda bahkan tidak perlu menyebutkan nama sesi layar Anda dan itu akan berfungsi dengan baik, tetapi begitu Anda terhubung dengannya, Anda tetap ingin membiarkannya tetap berjalan sepanjang waktu. ;-)

Tentu saja, jika Anda melakukannya, cara lain yang baik untuk melakukannya adalah dengan memberi nama salah satu jendela "antrian" dan menggunakan:

screen -S queue -p queue -X stuff "command"
Jordan
sumber
Sepertinya ini pada dasarnya hanya "mengetik" perintah di sesi layar yang sedang berjalan, sehingga ketika shell mendapatkan kontrol lagi setelah perintah pertama selesai, perintah ini akan mulai. Dengan kata lain, ini setara dengan solusi @ mankoff, tetapi menggunakan alat yang lebih bagus untuk melakukan pengetikan.
Ken Williams
Cukup banyak - perbedaan utama adalah bahwa solusi layar mendukung otomatisasi yang lebih baik. Anda dapat melakukan beberapa hal dengan tangan, hal-hal lain dengan skrip, semua dengan antarmuka yang sederhana.
Jordan
@ Jordan Sangat bagus, ini bekerja untuk saya. Tapi apa "barang" untuk setelah -X?
Konstantin
@Konstantin gnu.org/software/screen/manual/html_node/Paste.html#Paste (TL; DR - barang apa pun yang masuk ke terminal seolah-olah Anda mengetiknya)
Jordan
@ Jordan Oh, saya mengerti sekarang. Itu adalah perintah. Saya pikir itu adalah string yang sewenang-wenang.
Konstantin
8

Ada sebuah utilitas yang saya gunakan dengan sukses besar untuk persis use case yang Anda gambarkan. Baru-baru ini saya memindahkan laptop utama saya ke perangkat keras baru, yang melibatkan pemindahan beberapa file ke NAS dan sisanya ke mesin baru.

Beginilah cara saya melakukannya.

  1. Atur semua mesin yang terlibat dengan koneksi jaringan sehingga mereka dapat saling menjangkau.

  2. Pada mesin tempat Anda memindahkan file (selanjutnya disebut mesin sumber), instal rsync with apt-get install rsyncdan Spooler Task -sauce rahasia (situs web http://vicerveza.homeunix.net/~viric/soft/ts/ ). Jika Anda menggunakan Debian nama paket untuk tsis task-spoolerdan executable diganti namanya tspuntuk menghindari bentrokan nama dengan tsexecutable dari moreutilspaket. Paket Debian yang ditautkan dari situs web dapat diinstal dengan sempurna pada Ubuntu dengan dpkg -i task-spooler_0.7.3-1_amd64.debatau serupa.

  3. Pastikan juga semua mesin memiliki SSH terinstal apt-get install openssh-server. Pada mesin sumber, Anda perlu mengatur SSH untuk memungkinkan login tanpa kata sandi ke mesin target. Metode yang paling banyak digunakan adalah otentikasi kunci publik dengan ssh-agent(lihat https://www.google.se/search?q=ssh+public+key+authentication untuk contoh-contoh itu), tetapi kadang-kadang saya menggunakan metode yang lebih mudah yang hanya berfungsi juga dengan otentikasi kata sandi. Tambahkan yang berikut ini ke konfigurasi klien SSH Anda (salah satu ~/.ssh/configatau /etc/ssh/ssh_config):

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

    Kemudian buka satu terminal di mesin sumber, login dengan ssh target1, otentikasi seperti biasa, dan kemudian biarkan terminal ini terbuka. Perhatikan bahwa ada file socket bernama ~/.ssh/master-user@target1:22, ini adalah file yang akan membuat sesi master tetap otentik terbuka dan memungkinkan koneksi tanpa kata sandi berikutnya untuk user(selama koneksi menggunakan nama host dan port target yang sama).

    Pada titik ini Anda perlu memverifikasi bahwa Anda dapat masuk tanpa diminta untuk otentikasi ke mesin target.

  4. Sekarang jalankan ts rsync -ave ssh bigfile user@target1:untuk satu file atau ts rsync -ave ssh bigdir user@target1:untuk direktori. Dengan rsync, penting untuk tidak menyertakan garis miring pada direktori ( bigdirdibandingkan dengan bigdir/) atau rsync akan menganggap bahwa maksud Anda sama dengan bigdir/*di sebagian besar alat lainnya.

    Task Spooler akan mengembalikan prompt dan membiarkan Anda mengantri banyak dari perintah ini secara berurutan. Periksa antrian jalankan dengan tstanpa argumen.

Task Spooler memiliki banyak fitur seperti menata ulang antrian proses, menjalankan pekerjaan tertentu hanya jika pekerjaan lain berjalan dengan sukses, dll. Lihat bantuan dengan ts -h. Saya kadang-kadang memeriksa output perintah ketika sedang berjalan dengan ts -c.

Ada metode lain untuk melakukan ini tetapi untuk kasus penggunaan Anda, mereka semua termasuk Pengumpul Tugas. Saya memilih untuk menggunakan rsync di atas SSH untuk menjaga stempel waktu file, yang tidak akan disalin oleh SMB.

holmb
sumber
terima kasih atas jawaban Anda, saya tidak tahu ts, tampaknya sangat kuat dan mudah digunakan, hanya bercabang pada github autotoolized dan debianized.
Alex
@Alex Saya telah melihat garpu Anda dan terutama tertarik pada apa yang dilakukan sehubungan dengan autotooling dan debianizing sumber asli, dan melihat komitmen Anda itu tidak tersedia sebagai diff ke sumber aslinya. Maukah Anda memaksakan mendorong komitmen baru yang pada langkah 1. mengimpor sumber asli dan 2. berkomitmen dengan tambahan Anda? Ini akan membantu seseorang menjelajah sumber Anda untuk (lebih mudah) mempercayai penambahan Anda ke sumber asli. Ini adalah salah satu dari beberapa paket yang tidak saya instal dari PPA atau sejenisnya sehingga akan menyenangkan untuk membangunnya sendiri dengan garpu Anda.
holmb
Anda tahu saya harus mengganti kacamata saya, saya kehilangan bagian dari jawaban Anda tentang yang ada task-spooler:-) ... Lagi pula, yang ada di komentar Anda adalah saran yang sangat bagus, saya akan segera melakukannya.
Alex
selesai, dihapus, dan dibuat ulang repositori dengan komitmen progresif, hanya beberapa kesalahan (harus memetabolisme lebih banyak komit lokal sebelum mendorong)
Alex
4

Saya perlu hal-hal seperti ini cukup sering juga. Saya menulis sebuah utilitas kecil yang disebut afteryang mengeksekusi perintah setiap kali beberapa proses lainnya telah selesai. Ini terlihat seperti ini:

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

Anda kemudian menjalankannya seperti ini:

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

Keuntungan besar untuk ini dibandingkan beberapa pendekatan lain adalah bahwa pekerjaan pertama tidak perlu dijalankan dengan cara khusus, Anda dapat mengikuti proses apa pun dengan pekerjaan baru Anda.

Ken Williams
sumber
Skrip bagus @ken. Meskipun saya akan merekomendasikan mencoba Task Spooler karena Anda tampaknya memerlukan ini dari waktu ke waktu. Lihat jawaban saya.
holmb
Terlihat rapi, terima kasih. Satu hal yang hilang dari TS tampaknya adalah kemampuan untuk mengikuti pekerjaan yang tidak dimulai di bawah TS. Meskipun saya kira Anda bisa memulai pekerjaan TS baru yang tujuannya hanya untuk menunggu proses yang ada selesai.
Ken Williams
Memang. Itu adalah aspek yang berguna dari solusi Anda.
holmb
2

Command1 && Command2

  • "&&" berarti bahwa perintah2 hanya berjalan setelah command1 selesai dengan kode pengembalian 0
  • Catatan: a || berarti command2 hanya berjalan setelah command1 selesai dengan kode kembali selain 0
naftuli
sumber
1

Anda bisa menambahkan perintah ke baris perintah shell yang sudah menjalankan perintah.

Baik mengetik dengan hati-hati, atau mengetiknya di tempat lain, memverifikasi, dan memotong-dan-tempel. Bahkan jika perintah saat ini memuntahkan garis output, Anda masih dapat mengetik sesuatu yang baru, tekan enter, dan itu akan berjalan ketika semua perintah berjalan atau dimasukkan sebelum selesai.

Contoh berikut. Anda dapat memotong dan menempel semuanya, atau memasukkan perintah berikutnya saat yang pertama berjalan (jika Anda mengetik sangat cepat), atau lebih mungkin saat yang kedua berjalan .:

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

sumber
0

cara hackiest yang dapat saya pikirkan adalah untuk mempertahankan "status" antrian dengan file-file kunci sederhana di / tmp. ketika file1.sh melakukan perintah cp, itu akan menyimpan file kunci (atau hardlink) di / tmp. setelah selesai, hapus file tersebut. setiap skrip lain harus mencari di / tmp untuk file kunci dengan skema penamaan yang Anda pilih. secara alami ini tunduk pada semua jenis kegagalan, tetapi itu sepele untuk mengatur dan dapat dilakukan sepenuhnya dalam bash.

Brad Clawsie
sumber
Sulit digunakan dalam praktik, karena mengharuskan setiap pekerjaan yang ingin Anda jalankan perlu dimodifikasi untuk menyimpan file kunci, dan perlu tahu (atau menerima sebagai parameter) yang mengunci file untuk digunakan. Bilamana mungkin, yang terbaik adalah memiliki antrian eksternal untuk pekerjaan itu.
Ken Williams