Làm thế nào tôi có thể đánh thức một kịch bản bash ngủ?


27

Có thể đánh thức một quá trình bị tạm dừng bằng cách sử dụng sleeplệnh?


Ví dụ: giả sử bạn có tập lệnh này:

#!/bin/bash
echo "I am tired"
sleep 8h
echo "I am fresh :)"

Sau 30 phút bạn phát hiện ra rằng bạn cần dừng kịch bản, nghĩa là bạn muốn bạn đã viết sleep 30mthay thế.

Bạn không muốn gọi kill PIDhoặc nhấn Ctrl+ C, từ đó lệnh cuối cùng không được thực thi và bạn sẽ vẫn mệt mỏi.

Có cách nào để đánh thức quá trình từ sleephoặc có thể sử dụng một lệnh khác hỗ trợ đánh thức? Các giải pháp cho cả quá trình nền và tiền cảnh đều được chào đón.


13
Hét vào nó thật to.
Doorknob

2
@Doorknob gawking không thực sự hoạt động. Lần trước tôi có một sleepquá trình ing, tôi pushdra khỏi giường.
imallett

Kịch bản của bạn đang thiếu một #!dòng. Và đó là vấn đề bởi vì câu trả lời cho câu hỏi của bạn phụ thuộc vào việc có bất kỳ -etrong #!dòng.
kasperd

1
@kasperd Xong. Vì tò mò: cờ -e có ảnh hưởng gì?
Bittenus

2
Theo mặc định, một tập lệnh sẽ tiếp tục sau một lỗi. Nếu bạn sử dụng #!/bin/bash -e, tập lệnh sẽ dừng lại sau một lỗi. Đơn giản chỉ cần giết lệnh ngủ sẽ được coi là một lỗi bằng bash. Điều đó có nghĩa là không -ecó câu trả lời khá đơn giản cho câu hỏi của bạn. Nếu -eđược sử dụng, nó sẽ trở nên khó khăn hơn rất nhiều vì bạn sẽ cần phải dừng quá trình ngủ mà không giết chết nó.
kasperd

Câu trả lời:


47

Khi tập lệnh Bash đang chạy sleep, đây là tập lệnh pstreecó thể trông như sau:

bash(10102)───sleep(8506)

Cả hai đều có ID tiến trình (PID), ngay cả khi chạy dưới dạng tập lệnh. Nếu chúng tôi muốn làm gián đoạn giấc ngủ, chúng tôi sẽ gửi kill 8506và phiên Bash sẽ tiếp tục ... Vấn đề là trong một môi trường có kịch bản, chúng tôi không biết về sleeplệnh của lệnh và không có con người để xem xét quá trình cây.

Chúng ta có thể nhận được PID của phiên Bash thông qua $$biến ma thuật. Nếu chúng ta có thể lưu trữ ở đâu đó, thì chúng ta có thể nhắm mục tiêu các phiên bản sleepđang chạy bên dưới PID đó. Đây là những gì tôi đã đưa vào kịch bản:

# write the current session's PID to file
echo $$ >> myscript.pid

# go to sleep for a long time
sleep 1000

Và sau đó chúng ta có thể nói pkillvới các sleeptrường hợp nuke chạy bên dưới PID đó:

pkill -P $(<myscript.pid) sleep

Một lần nữa, điều này tự giới hạn chỉ sleepcác tiến trình chạy trực tiếp dưới một phiên Bash đó. Miễn là PID được ghi lại một cách chính xác, điều này làm cho nó an toàn hơn rất nhiều so với killall sleephoặc pkill sleep, có thể nuke bất kỳ sleep quá trình nào trên hệ thống (cho phép quyền).

Chúng ta có thể chứng minh lý thuyết đó bằng ví dụ sau nơi chúng ta có ba phiên bash riêng biệt, hai phiên chạy sleep. Chỉ bởi vì chúng tôi chỉ định PID của phiên bash trên cùng bên trái, chỉ có nó sleepbị giết.

nhập mô tả hình ảnh ở đây


Một cách tiếp cận khác là đẩy sleepvào nền, lưu trữ PID của nó và sau đó đưa nó trở lại nền trước. Trong kịch bản:

sleep 1000 &
echo $! > myscript.sleep.pid
fg

Và để giết nó:

kill $(<myscript.sleep.pid)

5

Bạn có thể viết tập lệnh của mình để xử lý ("bẫy") các tín hiệu khác từ kill, v.v. để bạn có thể sửa đổi hành vi của tập lệnh khi cần. Xem người đàn ông bash:

SIGNALS
   When  bash  is  interactive,  in the absence of any traps, it ignores SIGTERM (so that kill 0 does not
   kill an interactive shell), and SIGINT is caught and handled (so that the wait builtin  is  interrupt-
   ible).   In all cases, bash ignores SIGQUIT.  If job control is in effect, bash ignores SIGTTIN, SIGT-
   TOU, and SIGTSTP.

   Non-builtin commands run by bash have signal handlers set to the values inherited by  the  shell  from
   its  parent.   When  job  control is not in effect, asynchronous commands ignore SIGINT and SIGQUIT in
   addition to these inherited handlers.  Commands run as a result of  command  substitution  ignore  the
   keyboard-generated job control signals SIGTTIN, SIGTTOU, and SIGTSTP.

   The shell exits by default upon receipt of a SIGHUP.  Before exiting, an interactive shell resends the
   SIGHUP to all jobs, running or stopped.  Stopped jobs are sent SIGCONT to ensure that they receive the
   SIGHUP.   To  prevent the shell from sending the signal to a particular job, it should be removed from
   the jobs table with the disown builtin (see SHELL BUILTIN COMMANDS below) or  marked  to  not  receive
   SIGHUP using disown -h.

   If  the huponexit shell option has been set with shopt, bash sends a SIGHUP to all jobs when an inter-
   active login shell exits.

   If bash is waiting for a command to complete and receives a signal for which a trap has been set,  the
   trap  will not be executed until the command completes.  When bash is waiting for an asynchronous com-
   mand via the wait builtin, the reception of a signal for which a trap has been set will cause the wait
   builtin  to  return immediately with an exit status greater than 128, immediately after which the trap
   is executed.

4

Bạn chỉ có thể giết giấc ngủ sẽ tiếp tục dòng tiếp theo của kịch bản:

pkill sleep

Lưu ý rằng điều này sẽ giết bất kỳ quá trình ngủ nào đang chạy trong hệ thống của bạn, không chỉ trong tập lệnh của bạn.


1

Tôi có một kịch bản bash ngủ bắt đầu bằng cách cronkhởi động. Kịch bản thức dậy mỗi phút và thiết lập độ sáng màn hình máy tính xách tay dựa trên mặt trời mọc và mặt trời lặn thu được từ internet. Giai đoạn chuyển đổi có thể định cấu hình của người dùng giữa toàn sáng và mờ hoàn toàn đòi hỏi phải tăng và giảm các giá trị theo 3, 4, 5 hoặc bất cứ điều gì được tính mỗi phút.

Oli thoáng chạm vào pstreecâu trả lời của mình nhưng từ chối vì nó sẽ giết tất cả các sleeptrường hợp. Điều này có thể tránh được bằng cách thu hẹp tìm kiếm bằng các tùy chọn pstree.

Sử dụng pstree -hchúng tôi thấy toàn bộ quyền thừa kế:

$ pstree -h
systemd─┬─ModemManager─┬─{gdbus}
                      └─{gmain}
        ├─NetworkManager─┬─dhclient
                        ├─dnsmasq
                        ├─{gdbus}
                        └─{gmain}
        ├─accounts-daemon─┬─{gdbus}
                         └─{gmain}
        ├─acpid
        ├─agetty
        ├─atd
        ├─avahi-daemon───avahi-daemon
        ├─cgmanager
        ├─colord─┬─{gdbus}
                └─{gmain}
        ├─cron───cron───sh───display-auto-br───sleep
        ├─cups-browsed─┬─{gdbus}
                      └─{gmain}
        ├─dbus-daemon
        ├─fwupd─┬─3*[{GUsbEventThread}]
               ├─{fwupd}
               ├─{gdbus}
               └─{gmain}
        ├─gnome-keyring-d─┬─{gdbus}
                         ├─{gmain}
                         └─{timer}
        ├─irqbalance
        ├─lightdm─┬─Xorg───3*[{Xorg}]
                 ├─lightdm─┬─upstart─┬─at-spi-bus-laun─┬─dbus-daemon
                                                    ├─{dconf worker}
                                                    ├─{gdbus}
                                                    └─{gmain}
                                   ├─at-spi2-registr─┬─{gdbus}
                                                    └─{gmain}
                                   ├─bamfdaemon─┬─{dconf worker}
                                               ├─{gdbus}
                                               └─{gmain}
                                   ├─chrome─┬─2*[cat]
                                           ├─chrome─┬─chrome─┬─2*[chrome─┬─{Chrome_ChildIOT}]
                                                                      ├─5*[{CompositorTileW}]]
                                                                      ├─{Compositor}]
                                                                      ├─{GpuMemoryThread}]
                                                                      ├─{MemoryInfra}]
                                                                      ├─{Renderer::FILE}]
                                                                      ├─{TaskSchedulerRe}]
                                                                      └─{TaskSchedulerSe}]
                                                           ├─7*[chrome─┬─{Chrome_ChildIOT}]
                                                                      ├─5*[{CompositorTileW}]]
                                                                      ├─{Compositor}]
                                                                      ├─{GpuMemoryThread}]
                                                                      ├─{MemoryInfra}]
                                                                      ├─{Renderer::FILE}]
                                                                      ├─{ScriptStreamerT}]
                                                                      ├─{TaskSchedulerRe}]
                                                                      └─{TaskSchedulerSe}]
                                                           ├─chrome─┬─{Chrome_ChildIOT}
                                                                   ├─5*[{CompositorTileW}]
                                                                   ├─{Compositor}
                                                                   ├─{GpuMemoryThread}
                                                                   ├─{Media}
                                                                   ├─{MemoryInfra}
                                                                   ├─{Renderer::FILE}
                                                                   ├─{ScriptStreamerT}
                                                                   ├─{TaskSchedulerRe}
                                                                   └─{TaskSchedulerSe}
                                                           └─2*[chrome─┬─{Chrome_ChildIOT}]
                                                                       ├─5*[{CompositorTileW}]]
                                                                       ├─{Compositor}]
                                                                       ├─{GpuMemoryThread}]
                                                                       ├─{Renderer::FILE}]
                                                                       ├─{ScriptStreamerT}]
                                                                       ├─{TaskSchedulerRe}]
                                                                       └─{TaskSchedulerSe}]
                                                   └─nacl_helper
                                           ├─chrome─┬─chrome
                                                   ├─{Chrome_ChildIOT}
                                                   ├─{MemoryInfra}
                                                   ├─{TaskSchedulerSe}
                                                   └─{Watchdog}
                                           ├─{AudioThread}
                                           ├─{BrowserWatchdog}
                                           ├─{Chrome_CacheThr}
                                           ├─{Chrome_DBThread}
                                           ├─{Chrome_FileThre}
                                           ├─{Chrome_FileUser}
                                           ├─{Chrome_HistoryT}
                                           ├─{Chrome_IOThread}
                                           ├─{Chrome_ProcessL}
                                           ├─{Chrome_SyncThre}
                                           ├─{CompositorTileW}
                                           ├─{CrShutdownDetec}
                                           ├─{D-Bus thread}
                                           ├─{Geolocation}
                                           ├─{IndexedDB}
                                           ├─{LevelDBEnv}
                                           ├─{MemoryInfra}
                                           ├─{NetworkChangeNo}
                                           ├─{Networking Priv}
                                           ├─4*[{TaskSchedulerBa}]
                                           ├─6*[{TaskSchedulerFo}]
                                           ├─{TaskSchedulerSe}
                                           ├─{WorkerPool/3166}
                                           ├─{WorkerPool/5824}
                                           ├─{WorkerPool/5898}
                                           ├─{WorkerPool/6601}
                                           ├─{WorkerPool/6603}
                                           ├─{WorkerPool/7313}
                                           ├─{chrome}
                                           ├─{dconf worker}
                                           ├─{extension_crash}
                                           ├─{gdbus}
                                           ├─{gmain}
                                           ├─{gpu-process_cra}
                                           ├─{inotify_reader}
                                           ├─{renderer_crash_}
                                           ├─{sandbox_ipc_thr}
                                           └─{threaded-ml}
                                   ├─compiz─┬─{dconf worker}
                                           ├─{gdbus}
                                           ├─{gmain}
                                           └─8*[{pool}]
                                   ├─conky───6*[{conky}]
                                   ├─2*[dbus-daemon]

( .... many lines deleted to fit in 30k limit .... )

        ├─vnstatd
        ├─whoopsie─┬─{gdbus}
                  └─{gmain}
        └─wpa_supplicant

Như bạn có thể thấy một thông tin đăng nhập Ubuntu thông thường chứa nhiều PID (ID tiến trình).

Chúng tôi có thể thu hẹp nó xuống tập lệnh đang chạy bằng cách sử dụng:

$ pstree -g -p | grep display-auto
  |-cron(1198,1198)---cron(1257,1198)---sh(1308,1308)---display-auto-br(1321,1308)---sleep(26552,1308)

Chúng tôi thấy:

  • cron đã bắt đầu một trình bao (ID tiến trình 1308 và ID phiên 1308)
  • Shell gọi chương trình của chúng tôi chạy theo tiến trình ID 1321 và ID phiên 1308 (khớp với vỏ)
  • Chương trình của chúng tôi gọi sleeptheo quy trình ID 26552 và một lần nữa ID phiên 1308

Tại thời điểm này, chúng ta có thể sử dụng pkill -s 1308và nó sẽ giết toàn bộ phiên bao gồm shell, chương trình của chúng ta display-auto-brightnesssleeplệnh. Thay vào đó, chúng tôi sẽ sử dụng kill 26552để chỉ giết lệnh ngủ buộc chương trình của chúng tôi phải thức dậy và điều chỉnh độ sáng.

Gõ này bằng tay trong nhà ga bạn thấy:

───────────────────────────────────────────────────────────────────────────────
rick@dell:~$ pstree -g -p | grep display-auto
             |-cron(1198,1198)---cron(1257,1198)---sh(1308,1308)---display-auto-br(1321,1308)---sleep(32362,1308)
───────────────────────────────────────────────────────────────────────────────
rick@dell:~$ sudo kill 32362
───────────────────────────────────────────────────────────────────────────────
rick@dell:~$ pstree -g -p | grep display-auto
             |-cron(1198,1198)---cron(1257,1198)---sh(1308,1308)---display-auto-br(1321,1308)---sleep(1279,1308)
───────────────────────────────────────────────────────────────────────────────
rick@dell:~$ sudo kill 1279
───────────────────────────────────────────────────────────────────────────────
rick@dell:~$ pstree -g -p | grep display-auto
             |-cron(1198,1198)---cron(1257,1198)---sh(1308,1308)---display-auto-br(1321,1308)---sleep(4440,1308)
───────────────────────────────────────────────────────────────────────────────
rick@dell:~$ 

Bước tiếp theo là làm điều đó khi máy tính xách tay thức dậy sau khi bị treo. Ví dụ: khi đóng nắp, nó tối hoàn toàn và độ sáng màn hình được đặt ở mức "300". Khi mở nắp, ánh sáng ban ngày và độ sáng cần được đặt thành "2000". Tất nhiên, chương trình sẽ tự thức dậy sau 1 đến 59 giây nhưng sẽ thoải mái hơn khi độ sáng được đặt ngay lập tức.

Tôi sẽ đăng các đình chỉ mã / resume sau khi nó được viết ra. Hy vọng cuối tuần này.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.