через деякий час щось робити (і, можливо, також показувати результат у консолі)


12

Я використовую сервер Ubuntu 16.04, і я хочу використовувати утиліту atв моєму поточному сеансі, щоб зробити щось за 1 хвилину (скажімо, an echo), не даючи конкретної дати та часу - лише на 1 хвилину вперед від поточного часу.

Не вдалося:

echo 'hi' | at 1m

Причина я вибираю atбільш sleepтому , що недоліки сну поточного сеансу і для них більше підходить для затримки команд в іншій сесії, а не один ми працюємо з великою частиною часу. AFAIR, atне так поводиться і не сприймає мою сесію.

Оновити_1

По відповіді Пійда Пайпера я спробував:

(sleep 1m; echo 'hi')  &

У мене є проблема з цим методом: потік "привіт" друкується всередині моєї основної підказки, а також додає порожню вторинну підказку ( _) прямо під основний рядок, який її містить, див.

USER@:~# (sleep 1m; echo 'hi')  &
[1] 22731
USER@:~# hi
^C
[1]+  Done

Оновити_2

Відповідь Пітера Корда я спробував:

(sleep 2 && echo -e '\nhi' && kill -WINCH $$ &)

Це працює належним чином у Bash 4.4, але, мабуть, не в деяких старих версіях (див. Коментарі у відповіді). Я особисто використовую Bash 4.3 у власних умовах.


2
Мені б хотілося, щоб прапори вбивства були у стилі GNU, і їх можна було б переставити, щоб це не звучало як "вбийте відростка"!
NH.

Відповіді:


6

Потік "привіт" друкується в моєму підказці (в stdin), а не в моємуstdout

Ні, це не "надруковано у вашому stdin".

Якщо ви натиснули return, він не намагатиметься запустити hiяк команду. Це просто те, що фонове зображення echoдрукувалося, hiпоки курсор був після вашого запиту.


Можливо, ви хочете надрукувати провідний новий рядок , наприклад (sleep 1m && echo -e '\nhi' &). (Налаштуйте за необхідності для echoвашої оболонки. Або використовуйте printfдля перенесення.)

Я поміщаю &всередину нижньої частини корпусу, щоб "відхилити" фонове завдання, щоб ви також уникали "шуму" [1]+ Done. З &&командами, що &застосовується , застосовується до всього ланцюжка складових команд, тому він повертається до підказки оболонки одразу замість того, щоб чекати sleepвиходу, як ви отримаєте з(sleep 1; echo ... &)

Ось що відбувається (із затримкою на 1 секунду):

peter@volta:~$ (sleep 1 && echo -e '\nhi' &)
peter@volta:~$ 
hi
       # cursor is at the start of this empty line.

Bash не знає, що echoщось надрукував, тому не знає, що йому потрібно повторно надрукувати своє запит або очистити екран. Це можна зробити вручну за допомогою control-L.

Ви можете написати функцію оболонки, яка отримує bash для повторного друку її підказки після echoзакінчення . Просто виконання echo "$PS1"не відтворює жодних вже введених символів. kill -WINCH $$в моїй системі отримує bash, щоб повторно надрукувати рядок підказок, не очищаючи екран, залишаючи hiна рядку сам перед запитом. SIGWINCH надсилається автоматично, коли зміни розміру WINdow, і відповідь Баша на нього трапляється робити те, що ми хочемо.

Це може працювати з іншими оболонками, але я не намагаюся зробити цей 100% портативний / POSIX. ( На жаль, це працює лише на bash4.4, а не bash4.3, або залежить від деяких налаштувань, про які я не знаю )

  # bash4.4
peter@volta:~$ (sleep 2 && echo -e '\nhi' && kill -WINCH $$ &)
peter@volta:~$ ljlksjksajflasdf dfas      # typed in 2 seconds
hi
peter@volta:~$ ljlksjksajflasdf dfas      # reprinted by Bash because of `kill -WINCH`

Ви можете легко зафіксувати це у функції оболонки, яка сприймає аргумент сну та повідомлення.

bash 4.3 не повторно друкує своє запит після SIGWINCH, тому це не працює. Я shopt -s checkwinsizeввімкнув обидві системи, але він працює лише в системі Bash 4.4 (Arch Linux).

Якщо це не працює, ви можете спробувати (sleep 2 && echo -e '\nhi' && echo "$PS1" &), що "працює", якщо командний рядок порожній. (Він також ігнорує встановлену можливість PROMPT_COMMAND.)


Немає дійсно чистого способу отримати термінальний вихід, щоб змішатись із тим, що ви могли б робити на своєму терміналі пізніше, коли таймер спрацює. Якщо ви посередині щось прокручуєте less, ви легко можете пропустити це.

Якщо ви шукаєте щось із інтерактивними результатами, пропоную відтворити аудіофайл. наприклад, з програвачем командного рядка типу mpv(приємна форка MPlayer2). Або виберіть відеофайл, щоб відкрилося нове вікно.

(sleep 1 && mpv /f/share/music/.../foo.ogg </dev/null &>/dev/null &)

Ви можете echoвідкрити новий xterm / konsole / gnome-термінал. Використовуйте опцію, яка зберігає термінал відкритим після завершення команди.


Дякую тобі, Девіде, і я заграв. Це дійсно найближче, що я отримав щодо того, що я прагну. Чи є спосіб оновити наступну команду, щоб імітувати Enterключову подію натискання, відразу після появи ехо, щоб я автоматично був повернутий у первинний запит консолі ? (sleep 2 && echo -e '\nhi' && kill -WINCH $$ &).
Arcticooling

@Arcticooling: kill -WINCH $$ дійсно оновити запрошення оболонки , що працює в терміналі. В цьому і полягала вся суть його використання. Натискання клавіші Enter подасть частково набрану команду, але WINCH не робить, як я показав. Якщо ви нічого не ввели, ви отримуєте порожнє запит.
Пітер Кордес

1
Якщо ви почали вводити rm -rf ~/some/directory, Enter в неправильний час потенційно може запуститися rm -rf ~/. (Порада з безпеки: закінчіть вводити шляхи, а потім керуйте а-а та перейдіть lsна rm -rf, тому жирові пальці Введіть у будь-який час не зіпсує ваш день.)
Пітер Кордес

Провідний, я виконаний, (sleep 2 && echo -e '\nhi' && kill -WINCH $$ &)і після того, як з'явилося відлуння, я отримав порожнє підказку, тільки після удару Enterя повернувся до основного підказки ... Вибачте, якщо я вас неправильно зрозумів, я зовсім новачок у Bash.
Arcticooling

@Arcticooling: Я використовую Bash 4.4 в Arch Linux, в емуляторі терміналу Konsole. Я сподівався, що моя команда переноситься принаймні на інші версії bash, але, можливо, ні :( Так, я просто тестувався в Bash 4.3 всередині screenсеансу (і тільки через SSH) на старій системі Ubuntu, і я отримав поведінку, яку ви описуєте.
Пітер Кордес

13

Правильне використання - at <timespec>де <timespec>специфікація часу. Ви також можете скористатися -fопцією, щоб вказати файл, який містить команди для виконання. Якщо -fі не використовується переадресація, at прочитає команди для виконання зі stdin (стандартний ввід).

У вашому прикладі, щоб виконати "якусь команду" (я вибрав "якусь команду" бути "ехо привіт" у наведеному нижче прикладі) одну хвилину одразу після натискання клавіші enter (зараз), призначена <timespec>для використання now + 1 minute. Отже, щоб отримати бажаний результат за допомогою однолінійного рішення, будь ласка, скористайтеся командою нижче:

echo 'echo hi' | at now + 1 minute

Це повинен (і зробить) запустити echo hiкоманду через одну хвилину. Проблема тут полягає в тому, що echo hiкоманда буде виконана командою at у фіктивній формі, а вихід буде надісланий на поштову скриньку користувача (якщо вона правильно налаштована - що вимагає більш роз'яснення щодо налаштування поштової скриньки в машина Unix і не входить в обсяг цього питання). Суть полягає в тому, що ви не зможете безпосередньо бачити результат echo hiв тому ж терміналі, який ви видали команду. Найпростіша альтернатива - перенаправити його на "якийсь файл", наприклад:

echo 'echo hi > /tmp/at.out' | at now + 1 minute

У наведеному вище прикладі "деякий файл" є, /tmp/at.outі очікуваний результат полягає в тому, що файл at.outпід / tmp створюється через одну хвилину і контактує з текстом "привіт".

Окрім now + 1 minuteнаведеного вище прикладу, можна використовувати багато інших часових специфікацій, навіть деякі складні. Команда at досить розумна, щоб інтерпретувати досить читабельні люди, такі як приклади нижче:

now + 1 day, 13:25, mid‐night, noon, ...

Щоб отримати докладнішу інформацію про можливі специфікації часу, перегляньте сторінку чоловіка, оскільки можливі зміни досить великі і можуть включати дати, відносний чи абсолютний час тощо.


2
atза замовчуванням надсилає вихід поштою, але це потрібно правильно налаштувати для роботи.
Саймон Ріхтер

Я пропоную 100 відповідей за відповідь. Будь ласка, прочитайте моє повідомлення з нагородою нижче та відредагуйте, щоб детальніше пояснити, що таке at <timespec>та прапор, який ви використовували, і якщо він відповідає Ubuntu 16.04 xenial.
Arcticooling

Гаразд, я збільшив рівень деталізації у відповіді, щоб вона стала більш дидактичною. Для деяких це може здатись небагатим, але я вважаю, що це не залишає сумнівів для сумнівів, оскільки чітко наводить приклади, які працюють і як вони також працюють.
Марсело

7

Запустіть sleepв нижній частині:

(sleep 60; echo -e '\nhi')  &

Примітка: в Linux ви можете навести аргумент, щоб заснути за секунди або з суфіксом s / m / h / d (на секунди, хвилини, години, дні). На BSD аргумент повинен бути за секунди


У мене є невелика проблема з цим методом --- потік "привіт" друкується в моєму підказці (в stdin), а не в моєму stdout(як це було б у звичайному echo).
Arcticooling

1
Якщо ви не хочете, щоб вихід у вашому терміналі змішувався з підказками та
висновками

Це перенаправлення не вдалося @PiedPiper (sleep 10s; echo 'hi') & 1>. Зараз я читаю докладніше про це.
Arcticooling

2
Читання документації - це завжди гарна ідея :)
PiedPiper

1
@Arcticooling Схоже, ви заплутані в значеннях stdinі stdout. Вони не мають нічого спільного з тим, де на вашому терміналі з'являються речі; натомість слід інтерпретувати їх стосовно певного процесу (в основному, програми). Стандартний вхід ("stdin") для процесу - це джерело, з якого процес може зчитувати дані, а стандартний висновок процесу ("stdout") - призначення, куди він може записувати дані. Ці джерела та пункти призначення можуть бути іншими програмами або файлами або самим терміналом (введені вами речі переходять до stdin, і відображається все, що стосується stdout).
David Z

3

Це не вдалося , тому що ви перенаправивши висновок echo "hi", який тільки hiдо at, але atочікує , що це вхід може бути виконана оболонкою системи по замовчуванням (зазвичай Баш, але іноді що - то інше в залежності від системи).

Це:

at 1m << EOF
echo "hi"
EOF

Ви досягнете того, що, схоже, намагаєтесь зробити. Він використовує конструкцію оболонки під назвою "тут документ", що є загальноприйнятим способом робити цей тип речей (тому що він обробляє кілька рядків краще, ніж використання echoкоманди і не вимагає створення нового файлу, як вам потрібно з cat) і перекладається на дещо складніший еквівалент, використовуючи echo:

echo 'echo "hi"' | at 1m

Напевно, варто відзначити, що atбудь-яка команда-вихід надсилатиметься користувачеві, який викликав atкоманду, замість того, щоб виводити висновок до терміналу, як команда, яка затримується з використанням sleepв нижній частині. Зокрема, це означає, що якщо ви не зробили певну настройку системи або не маєте наміру прочитати локальну котушку пошти, ви не зможете отримати вихід команд через at.


Чомусь обидва приклади, які ви подали, дають мені помилку syntax error. Last token seen: m Garbled time . Я поняття не маю, чому. Я використовую Ubuntu 16.04, Bash 4.0. Можливо, ви зробили це в іншій системі. Навіть коли я друкую просто atбез будь-яких додаткових аргументів --- я все одно отримую цю саму помилку. Більше даних тут .
Arcticooling

1
at 1mне працює для сумісного пози at. Командою потрібно було бat now + 1 minute
PiedPiper

@PiedPiper вірно, 1м не сумісний з версіями at, сумісними з POSIX , я просто припускав, що у вас є версія, яка прийняла цей синтаксис.
Остін Хеммельгарн

@PiedPiper, at 1mце не POSIX, але сумісні з POSIX реалізаціями atвільні інтерпретувати його так, як вони хочуть, але це не робить atреалізацію менш сумісною для того, щоб інтерпретувати її як те, що означає те саме, що і now + 1 minuteповернення помилки чи значення місяць тому . IOW, це at 1mкод, який не є POSIX.
Стефан Шазелас

2

Поєднайте відповідь @Peter Cordes та цю відповідь /programming/23125527/how-to-return-to-bash-prompt-after-printing-output-from-backgrounded-function/23125687#23125687

Код нижче - з останньої відповіді, з невеликою зміною моєї. Складіть його, щоб подати файл a.out (незалежно від імені)

#include <sys/ioctl.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>

int main(int argc, char *argv[])
{
        char *tty = "/dev/tty";
        if (argc > 1)
                tty = argv[1];
        int fd = open(tty, O_WRONLY);

        int i;
        char buf[] = "\n";
        for (i = 0; i < sizeof buf - 1; i++)
                if (ioctl(fd, TIOCSTI, &buf[i]))
                        perror("ioctl");
        close(fd);
        return 0;
}

Потім запустіть команду нижче. (Я ставлю a.out в dir / tmp /, можливо, вам доведеться змінити свій)

(sleep 2 && echo -e '\nhi' && /tmp/a.out &)

або

(sleep 2 && echo -e '\nhi' && /tmp/a.out /proc/$$/fd/0 &)

BTW, kill -WINCH $$для мене працює чудово з Bash 4.3 на Gentoo.


1

Спираючись на відповіді вище, ви можете вбудовувати команду направляти її на свій термінал, наприклад:

echo "echo hi >$(tty); kill -WINCH $$" | at now + 1 minute

ttyКоманда повертає шлях до пристрою вашого поточного терміналу, укладаючи його в $(...)має Баш виконати його в суб-оболонки, і вбити команду посилає сигнал з поточною діяльністю , який матиме Баш повторно роздрукувати його $ PS1 запрошення.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.