2017-06-04 46 views
2

我試圖用systemd執行shell腳本。系統單元文件tr問題

如果我從bash運行我的腳本,一切正常。但是,如果我通過systemd運行相同的腳本,它永遠不會結束。它似乎掛的命令是:

random="$(LC_ALL=C tr -cd '[:alnum:]' < /dev/urandom | fold -w128 | head -n1)" 

如果我有random="1234"替換該行還與systemd運行。我猜'掛'命令是tr - 它的過程永遠不會結束。

這是我使用的systemd單元文件:

[Unit] 
Description=my script 

[Service] 
Type=forking 
Restart=on-failure 
ExecStart=/mypath/script.sh start 
ExecStop=/bin/kill $MAINPID 
ExecStopPost=/bin/rm -f /mypath/RUNNING_PID 

[Install] 
WantedBy=multi-user.target 
+0

您的服務叉嗎?如果不是,那麼'Type = fork'是錯誤的服務類型。請參閱'man systemd.service'獲取選項。 –

+0

如果systemd發現腳本以非零狀態退出,那麼'Restart = on-failure'會重新啓動它。是'random =「$(LC_ALL = C tr -cd'[:alnum:]' alvits

+0

@alvits是的,我想重啓服務,如果它崩潰。並且:tr不是腳本中的最後一個命令。 – Kris

回答

2

編輯:作出的解釋更清晰,增加了新的信息。

簡短的回答:在.service文件[Service]下設置IgnoreSIGPIPE=false。從systemd.exec手冊:

IgnoreSIGPIPE= 
     Takes a boolean argument. If true, causes 
     SIGPIPE to be ignored in the executed process. 
     Defaults to true because SIGPIPE generally is 
     useful only in shell pipelines. 

龍解釋

random="$(LC_ALL=C tr -cd '[:alnum:]' < /dev/urandom | fold -w128 | head -n1)"

head命令退出從fold收到的第一個換行符後,它是開放的文件描述符被關閉。當fold命令稍後嘗試寫入管道時,它將收到一個SIGPIPE信號。該信號的默認操作是該過程的終止。這通常應導致終止命令fold,同樣也會終止命令tr

但是,當流水線在systemd下運行時,systemdSIGPIPE的默認操作設置爲SIG_IGN,這使流水線中的進程忽略該信號。雖然fold命令忽略該信號,但它在寫入損壞的管道時仍會收到EPIPE錯誤。但fold命令不檢查任何fwrite調用的返回值,至少不在coreutils-8.26中。這會導致fold命令繼續從std in中讀取,而忽略該錯誤,寫入std out。這樣做,fold保持從tr管道打開。由於tr也會忽略SIGPIPE,而到fold的管道已打開,因此它只會繼續從/dev/urandom讀取數據並將過濾後的字節永久寫入管道。

+0

此'重新啓動=失敗'影響行爲。您已經計算出退出狀態。 – alvits

+0

謝謝湯姆!我查找了IgnoreSIGPIPE,它看起來像默認爲true:https://www.freedesktop.org/software/systemd/man/systemd.exec.html#IgnoreSIGPIPE=。但是之前你寫的 - 在你編輯答案之前 - 實際上幫助了我:)。如果我使用'$(LC_ALL = C tr -cd'[:alnum:]'/dev/null | dd bs = 128 count = 1 2>/dev/null)我交換了'fold -w128 |頭'-n1'與'dd bs = 128 count = 1'像你之前建議的那樣。我必須添加'2>/dev/null'來擺脫位於journalctl中的'tr:write error:Broken pipe'。所以我會檢查你的答案是否與以前一樣:) – Kris

+0

你的原始答案是一種解決方法。但是這個修改後的答案絕對是答案。感謝您引用手冊頁,它可以幫助社區中的每個人。 – alvits