gpt4 book ai didi

linux - Shell 脚本挂起,但仅在调用变量或 strace 时

转载 作者:IT王子 更新时间:2023-10-29 00:39:09 27 4
gpt4 key购买 nike

一般问题:如果调用它的脚本或 shell (bash) 命令将它调用到一个变量中,什么会导致本身运行良好的脚本挂起?

换句话说,怎么会有这样调用的脚本... /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 中,它也会挂起。 .

奇怪的是,其他脚本以相同的方式以相同的语法调用,例如sbin/service httpd start ,当被调用到一个变量时工作得很好。因此,很明显,当输出存储为变量时,脚本可能会挂起,但如果不是这种情况,则运行得很好。

以下是测试哪些调用挂起,哪些不挂起的结果:

挂机 ------------------------------------------------

  • 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,这里有一些观察:
  • 从许多看起来像脚本按预期运行的事件开始。
  • 然后,日志文件的最后 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

    所以死亡螺旋前的最后一行是 read()在 channel 12 上。然后它只是循环 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 确实是解决此类问题的一般方法,但我不知何故做错了,导致了这些错误。

    最佳答案

    我很确定问题在于 shell 正在捕获/sbin/service 脚本和它启动的 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]

    关于linux - Shell 脚本挂起,但仅在调用变量或 strace 时,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13782039/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com