Из статьи Википедии о демонах :
В среде Unix родительский процесс демона часто, но не всегда, является процессом инициализации. Демон обычно создается либо процессом, разветвляющим дочерний процесс, а затем немедленно завершающимся, что заставляет init принять дочерний процесс, либо процессом init, непосредственно запускающим демон. Кроме того, демон, запускаемый путем разветвления и выхода, обычно должен выполнять другие операции, такие как отключение процесса от любого управляющего терминала (tty). Такие процедуры часто реализуются в различных вспомогательных подпрограммах, таких как daemon (3) в Unix.
Прочтите справочную страницу функции демона
.
Запуск фоновой команды из оболочки, которая немедленно завершает работу, приводит к тому, что PPID процесса становится 1. Легко проверить:
# bash -c 'nohup sleep 10000 &>/dev/null & jobs -p %1'
1936
# ps -p 1936
PID PPID PGID WINPID TTY UID STIME COMMAND
1936 1 9104 9552 cons0 1009 17:28:12 /usr/bin/sleep
Как видите, процесс принадлежит PID 1, но все еще связан с TTY. Если я выйду из этой оболочки входа, затем снова войду и снова сделаю ps
, TTY станет ?
.
Прочтите, почему важно отключиться от TTY .
Использование setsid
(часть util-linux
):
# bash -c 'cd /; setsid sleep 10000 /dev/null & jobs -p %1'
9864
# ps -p 9864
PID PPID PGID WINPID TTY UID STIME COMMAND
9864 1 9864 6632 ? 1009 17:40:35 /usr/bin/sleep
Я думаю, вам даже не нужно перенаправлять stdin, stdout и stderr.
while read -r line; do
date=$(grep -Eo "201.{12}.M," <<< "$line")
phrase=$(grep -Eo "certain phrase" <<< "$line")
echo "${date}${phrase:-NULL}"
done < test.txt
Вы читали строку, но не искали ее. Я подправил регулярное выражение в первом grep, чтобы оно соответствовало дате (вместо -c
ее подсчета). Последней частью головоломки было отображение переменной $phrase с расширением параметра, чтобы заменить пустое значение словом «NULL».
Вместо grep
ping в while
выполните все в одном sed
скрипте:
sed 's/\( *[0-9]*,[^,]*,\).*\(certain phrase[^ ]*\).*/\1\2/;t
s/\( *[0-9]*,[^,]*,\).*/\1NULL/' file.txt
sed
уже обрабатывает за вас построчно, и в каждой строке скрипт выполняет замену командой s
:
Первая часть [0-9]*, [^,]*,
должно соответствовать строке даты. Окружая его \(\)
, мы можем повторно использовать его в замене как \1
То же самое для второго \(\)
, содержащего фразу и конечные непустые (при необходимости адаптируйте), которые обозначаются как \2
. Все остальное выбрасывается.
Если эта замена была сделана, команда t
переходит в конец скрипта, как мы и сделали. Если замена невозможна, все после даты заменяется на NONE
Я бы предложил что-то вроде
awk 'BEGIN {OFS=FS=","}
/201/ {
if (match($0,"certain phrase")) {
print $1, $2, substr($0,RSTART,RLENGTH+1)
} else {
print $1, $2, "NULL"
}
}' file
Тестирование с вашими входными данными:
$ awk 'BEGIN {OFS=FS=","}
> /201/ {
> if (match($0,"certain phrase")) {
> print $1, $2, substr($0,RSTART,RLENGTH+1)
> } else {
> print $1, $2, "NULL"
> }
> }' file
20170101,05:00 AM,certain phrase1
20170102,09:30 AM,certain phrase2
20170103,05:30 AM,NULL
perl -lne 'print /^((?:.+?,){2})/, /\h\K(certain\h+phrase\d+)/ ? $1 : "NULL"' < test.txt
Здесь мы получаем первые два поля, разделенные запятыми, а затем ищем "определенная фраза". Если он найден, используйте его, иначе используется «NULL».