Shell脚本挂起,但只有调用variables或strace时

一般问题:什么可能会导致一个脚本本身工作正常,挂起如果脚本或shellbash)命令调用它调用它成为一个variables?

换句话说,如何调用这样的脚本? /path/to/script arg arg …失败并挂起时调用像这样… VAR=$(/path/to/script arg arg);


(主要编辑注意到一个软件故障导致许多初始testing给出不正确的结果)


我的具体情况:我有一个脚本,可以正常工作(启动,停止或重新启动Java应用程序Apache Solr, 从这里改编 )。 代码如下,其命令是sbin/service solr [action] ,例如sbin/service solr start

当从脚本或直接从控制台(在我的情况下是bash )调用,如sbin/service solr start ,它工作正常,并迅速完成。 但是,如果将其调用到variables中,如VAR=$(sbin/service solr start); ,它的工作原理,但挂钩futext / clock_gettime循环(下面的跟踪)。 它也挂起,如果它被称为不是一个variables,而是strace

奇怪的是,用相同的语法调用的其他脚本(例如sbin/service httpd start在调用variables时工作得很好。 所以很明显可能会有一些脚本会在输出存储为variables时挂起,但是如果不是这种情况,可以很好地运行。


以下是testing哪些调用挂起和哪些不挂起的结果:

吊椅 ————————————————

  • 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

与我第一次想到的相反。 这会输出一个简单的更新消息,理想情况下,我们会捕获variables和日志 – 但试图这样做会导致它挂起。

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

挂起的语法在其他service脚本上工作得很好,并且脚本的输出被传递给variables而没有问题。


下面是该脚本的完整代码:(注释已被删除,自然,$ SOLR_DIRpath在真实脚本中是真实的)

 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 (脚本中指定的日志文件)中没有错误或任何exception。 Centos Linux服务器,如果这是相关的。


为了回应问题的早期版本,@cdarkebuild议我在调用strace -f -o strace.out /path/to/script上运行strace -f -o strace.out /path/to/script script,并查找(massive!)输出文件strace.out 。 接近3mbs,这里有一些观察:

  1. 从很多活动开始,看起来像脚本function的预期。

  2. 然后,最后的15%左右的日志文件是这样的,重复不同的整数,但看起来相同的hex代码:

 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 

即使在脚本仍在运行的情况下执行 ps -p这些PID也没有任何结果,而输出文件仍在变大,而这些代码行仍在写入 。 我不太确定这是可能的。

最后一部分显然是正确执行的脚本( solr/solr.xml是一个Solrconfiguration文件,需要读取以启动它), 然后才进入最后一部分输出, 然后进入永不退出的futex / clock_gettime循环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,直到手动死亡。


最后一点可能是无关紧要的,但是如果类似于这个问题 ,我运行使用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真的是这样的问题的一般修复,但我做错了某种程度上,导致这些错误。

我很确定问题是shell正在捕获/ sbin / service脚本它启动的solr服务的输出,因此会在继续之前等待服务退出(或者至少关闭它的stdout)。 这是一个简单的演示:

 $ 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]