2012-12-08 70 views
5

一般問題:如果腳本或調用它的shell(bash)命令調用它爲一個腳本,變量?Shell腳本掛起,但僅在調用變量或strace時纔會掛起

換句話說,怎麼會有這樣的腳本工作,當這樣的調用... /path/to/script arg arg ...失敗並掛起時,這樣的調用... VAR=$(/path/to/script arg arg);?我有一個腳本,它工作正常(:



我的具體情況(主要編輯注意到,軟件故障引起了很大的初步測試給出不正確的結果後)啓動,停止或重新啓動Java應用程序Apache Solr,adapted from here)。代碼如下,其命令是sbin/service solr [action],例如sbin/service solr start

當從腳本或直接從控制檯(bash在我的情況下)調用,如sbin/service solr start,它工作正常,並迅速完成。但是,如果它被調用到變量中,例如VAR=$(sbin/service solr start);,它可以工作,但會掛載一個futext/clock_gettime循環(以下跟蹤)。它也掛起,如果它被稱爲不是一個變量,但strace

奇怪的是,其他腳本以相同的語法調用,例如,當調用一個變量時,工作得很好。所以顯然有可能會有一些關於腳本的東西,當輸出存儲爲變量時會使其掛起,但如果不是這種情況,則可以很好地運行。


下面是測試什麼叫掛的結果,什麼都不用:

掛起 ---------------------- --------------------------

  • VAR=$(/sbin/service solr start);
  • VAR=$(source /sbin/service solr start);
  • VAR=$(nohup /sbin/service solr start &);

(因此,調用哪個進程並不重要)另外,編輯腳本文件以使用source啓動服務會導致服務無法工作。

不掛 -------------------------------------

  • VAR=$(/sbin/service solr start >> /dev/null);

輸出到/dev/null允許我們要求輸出,而不使其掛起。然而,由於沒有收到實際的輸出,所以沒有多大用處。

  • /sbin/service solr start

相反的是我首先想到的。這會輸出一個簡單的更新消息,理想情況下,我們會在變量和日誌中捕獲 - 但試圖這樣做會導致它掛起。

  • VAR=$(/sbin/service httpd restart);

是掛起作品只是在其他service腳本精細的語法,腳本的輸出傳遞給變量沒有問題。


下面是腳本的完整代碼:(註釋去掉,自然是$ SOLR_DIR路徑是真正的腳本是真實的)

SOLR_DIR="[path/to/application]" 
JAVA_OPTIONS="-Xms64m -Xmx64m -DSTOP.PORT=8079 -DSTOP.KEY=mustard -jar start.jar" 
LOG_FILE="/var/log/solr.log" 
JAVA="/usr/bin/java" 

case $1 in 
    start) 
     echo "Starting Solr" 
     cd $SOLR_DIR 
     $JAVA $JAVA_OPTIONS 2> $LOG_FILE & 
     ;; 
    stop) 
     echo "Stopping Solr" 
     cd $SOLR_DIR 
     $JAVA $JAVA_OPTIONS --stop 
     ;; 
    restart) 
     $0 stop 
     sleep 1 
     $0 start 
     ;; 
    *) 
     echo "Usage: $0 {start|stop|restart}" >&2 
     exit 1 
     ;; 
esac 

沒有錯誤或任何不尋常var/log/solr.log(日誌在腳本中命名的文件)。 Centos Linux服務器,如果這是相關的。


在回答這個問題的早期版本,@cdarke建議我在腳本中調用這個腳本運行strace -f -o strace.out /path/to/script,並期待在(龐大!)輸出文件strace.out。這幾乎是3mbs,這裏的一些意見:

  1. 開始有很多的活動,看起來像腳本功能按預期的。

  2. 然後,在過去的15%左右的日誌文件是這樣的,重複用不同的整數,但看似相同的十六進制代碼:

...

25687 futex(0x688d454, FUTEX_WAIT_PRIVATE, 1, {0, 49980000}) = -1 ETIMEDOUT (Connection timed out) 
25687 futex(0x688d428, FUTEX_WAKE_PRIVATE, 1) = 0 
25687 clock_gettime(CLOCK_MONOTONIC, {39074112, 932735888}) = 0 
25687 clock_gettime(CLOCK_REALTIME, {1355007234, 333458000}) = 0 

這些PID即使我在腳本仍在運行時輸入ps -p也沒有任何結果,而輸出文件仍然變大,而這些代碼行仍在寫入。我不太確定這是可能的。

這裏的前的最後位了輸出它得到永無止境的futex的/ clock_gettime循環,的最後一部分,這顯然是正確執行腳本(solr/solr.xml是Solr的配置文件,這需要讀取啓動Solr的過程):

25874 stat("solr/solr.xml", {st_mode=S_IFREG|0777, st_size=1320, ...}) = 0 
25874 write(2, "Dec 8, 2012 5:12:05 PM org.apach"..., 106) = 106 
25874 socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 89 
25874 fcntl(89, F_GETFL)    = 0x2 (flags O_RDWR) 
25874 fcntl(89, F_SETFL, O_RDWR|O_NONBLOCK) = 0 
25874 setsockopt(89, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 
25874 bind(89, {sa_family=AF_INET, sin_port=htons(8983), sin_addr=inet_addr("0.0.0.0")}, 16) = 0 
25874 listen(89, 50)     = 0 
25874 setsockopt(89, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 
25874 lseek(12, 57747, SEEK_SET)  = 57747 
25874 read(12, "PK\3\4\n\0\0\0\10\0\221Vi>F\347\254\364\325\4\0\0002\t\0\0002\0\0\0", 30) = 30 
25874 lseek(12, 57827, SEEK_SET)  = 57827 
25874 read(12, "\225V\377oSU\24\377\334\273\256\257_\36l\216m\254\262\351\224\241]\273\255\200\314/\5\246c\200"..., 1237) = 1237 
25874 futex(0x2aaab0173054, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x2aaab0173050, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1} <unfinished ...> 
25894 <... futex resumed>)    = 0 
25894 futex(0x2aaab0173028, FUTEX_WAIT_PRIVATE, 2, NULL <unfinished ...> 
25874 <... futex resumed>)    = 1 
25874 futex(0x2aaab0173028, FUTEX_WAKE_PRIVATE, 1 <unfinished ...> 
25894 <... futex resumed>)    = 0 
25894 futex(0x2aaab0173028, FUTEX_WAKE_PRIVATE, 1) = 0 
25894 clock_gettime(CLOCK_REALTIME, {1355008325, 376033000}) = 0 
25894 futex(0x2aaab0173054, FUTEX_WAIT_PRIVATE, 3, {0, 983000} <unfinished ...> 
25874 <... futex resumed>)    = 1 
25874 futex(0x2aaab0173054, FUTEX_WAKE_OP_PRIVATE, 1, 1, 0x2aaab0173050, {FUTEX_OP_SET, 0, FUTEX_OP_CMP_GT, 1} <unfinished ...> 
25894 <... futex resumed>)    = 0 
25894 futex(0x2aaab0173028, FUTEX_WAIT_PRIVATE, 2, NULL <unfinished ...> 
25874 <... futex resumed>)    = 1 
25874 futex(0x2aaab0173028, FUTEX_WAKE_PRIVATE, 1 <unfinished ...> 
25894 <... futex resumed>)    = 0 
25894 futex(0x2aaab0173028, FUTEX_WAKE_PRIVATE, 1) = 0 
25894 poll([{fd=89, events=POLLIN|POLLERR}], 1, -1 <unfinished ...> 
25874 <... futex resumed>)    = 1 
25874 write(2, "2012-12-08 17:12:05.376:INFO::St"..., 66) = 66 
25874 write(2, "\n", 1)     = 1 
25874 mmap(0x41348000, 12288, PROT_NONE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0) = 0x41348000 
25874 rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0 
25874 sched_getaffinity(25874, 32, { ffff, 0, 0, 0 }) = 32 
25874 sched_getaffinity(25874, 32, { ffff, 0, 0, 0 }) = 32 
25874 gettid()       = 25874 
25874 rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0 
25874 rt_sigprocmask(SIG_UNBLOCK, [HUP ILL BUS FPE SEGV USR2 TERM], NULL, 8) = 0 
25874 rt_sigprocmask(SIG_BLOCK, [QUIT], NULL, 8) = 0 
25874 mmap(0x41348000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x41348000 
25874 mprotect(0x41348000, 12288, PROT_NONE) = 0 
25874 futex(0x10632d54, FUTEX_WAIT_PRIVATE, 1, NULL <unfinished ...> 
25882 <... futex resumed>)    = -1 ETIMEDOUT (Connection timed out) 
25882 futex(0x106cc428, FUTEX_WAKE_PRIVATE, 1) = 0 
25882 clock_gettime(CLOCK_MONOTONIC, {39075204, 21489888}) = 0 
25882 clock_gettime(CLOCK_REALTIME, {1355008325, 422198000}) = 0 
25882 futex(0x106cc454, FUTEX_WAIT_PRIVATE, 1, {0, 49984000}) = -1 ETIMEDOUT (Connection timed out) 
25882 futex(0x106cc428, FUTEX_WAKE_PRIVATE, 1) = 0 
25882 clock_gettime(CLOCK_MONOTONIC, {39075204, 72479888}) = 0 
25882 clock_gettime(CLOCK_REALTIME, {1355008325, 473185000}) = 0 
25882 futex(0x106cc454, FUTEX_WAIT_PRIVATE, 1, {0, 49987000}) = -1 ETIMEDOUT (Connection timed out) 
25882 futex(0x106cc428, FUTEX_WAKE_PRIVATE, 1) = 0 

因此死亡纏繞之前的最後一行是在信道12上read()然後,它只是循環futex的和clock_gettime直到它的手動殺死。


最後這一點可能是無關緊要的,但如果similar to in this question,我運行使用nohup和轉移輸出到/dev/null調用該腳本的劇本,我得到附近展開以下(約100KB到輸出文件) :巨大的,這些號碼:

25664 close(67) = -1 EBADF (Bad file descriptor)

他們從67去,增加+1每次到:

25664 close(1023) = -1 EBADF (Bad file descriptor)

然後他們接着

25664 open("/dev/null", O_RDWR) = 3

同樣,PID是空的,到目前爲止,我所看到的。不知道這是否是相關的 - 我想這會打開使用nohup與輸出到/ dev/null真的是一個像這樣的問題的一般修復,但我做錯了某種方式,導致這些錯誤。

+0

哪個shell?例如,ksh93將使用'exec'在腳本中執行最終命令,所以您不一定會看到兩個進程。我們需要知道'掛'是否在等待某件事情,如信號。嘗試運行'strace -f -o strace.out ScriptB'。然後看看strace.out(它會很大)。這應該跟蹤內核調用並顯示它是否在等待任何內容。 – cdarke

+0

@cdarke感謝您的帖子。回覆。哪個shell:'ps -p $$ -o comm,args'給我''bash'帶參數'-bash'。回覆。 'strace' - 你是對的,差不多3mbs!我將把該文件中的觀察結果編輯到問題中。 – user568458

+0

@cdarke我已經編輯了所有看起來相關的輸出,以及通過查找這些進程的PID可以獲得的非常有限的信息。非常感謝您的幫助,請確定是否有任何特定的內容我應該在輸出中查找。 – user568458

回答

2

我敢肯定的問題是,外殼捕獲輸出從/ sbin目錄/服務腳本啓動Solr的服務,因此將等待服務退出(或至少接近它的標準輸出),然後繼續。這裏有一個簡單的演示:

$ bg_service() { while true; do sleep 10; done; } 
$ start_bg_service() { echo "starting"; bg_service& echo "running"; } 
$ start_bg_service 
starting 
[1] 8656 
running 
$ var=$(start_bg_service) 
[It hangs at this point... until I open another shell and kill the background process] 
+0

聽起來很可能。關於如何以不捕獲嵌套腳本輸出並掛起的方式啓動solr服務的任何想法?我想調用啓動腳本來從啓動腳本本身捕獲輸出,並從啓動腳本啓動的進程輸出以轉到日誌文件,並被調用它的父節點忽略 – user568458

+1

啓動腳本當前重定向stderr的服務器日誌;只需修改它就可以在那裏重定向stdout:'$ JAVA $ JAVA_OPTIONS&> $ LOG_FILE&' –

+0

很酷。根據你的評論,我使用'$ JAVA $ JAVA_OPTIONS 1>/dev/null 2> $ LOG_FILE&'來放棄標準輸出並記錄stderr,這更接近於前面的設置(記錄錯誤但不記錄標準輸出)。相同的原則,完美的作品!謝謝:) – user568458