代码之家  ›  专栏  ›  技术社区  ›  Paul

Bash wait命令忽略指定的进程ID

  •  0
  • Paul  · 技术社区  · 3 年前
    DIRECTORIES=( group1 group2 group3 group4 group5 )
    PIDS=()
    
    function GetFileSpace() {
        shopt -s nullglob
        TARGETS=(/home/${1}/data/*)
        for ITEM in "${TARGETS[@]}"
        do
                # Here we launch du on a user in the background
                # And then add their process id to PIDS
                du -hs $ITEM >> ./${1}_filespace.txt &
                PIDS+=($!)
        done
    }
    
    # Here I launch function GetFileSpace for each group.
    for GROUP in "${DIRECTORIES[@]}"
    do
        echo $GROUP
        # Store standard error to collect files with bad permissions
        GetFileSpace $GROUP 2>> ./${GROUP}_permission_denied.txt &
    done
    
    for PID in "${PIDS[@]}"
    do
        wait $PID
    done
    
    echo "Formatting Results..."
    # The script will after this, but it isn't relevant.
    

    我正在尝试编写一个脚本,用于跨5个组监视单个用户的存储卷和文件权限。

    |_home          # For additional reference to understand my code,
      |_group1      # directories are laid out like this
      | |_data
      |   |_user1
      |   |_user2
      |   |_user3
      |
      |_group2
        |_data
          |_user4
          |_user5
    

    首先,我使用循环以迭代方式启动函数, GetFileSpace ,对于中的每个组 DIRECTORIES . 然后运行此函数 du -sh 对于组中找到的每个用户。

    为了加快整个过程,我启动了 获取文件空间 以及随后的 du-sh 后台的子进程 & . 这使得一切都可以几乎同时运行,所需时间少得多。

    我的问题是,在我启动这些流程之后 我希望脚本等待的每个后台实例 du-sh 在继续下一步之前完成 .

    为此,我尝试在阵列中启动每个任务后收集进程ID PIDS . 然后,我尝试在数组中循环并等待每个PID,直到所有子进程完成。不幸的是,这似乎不起作用。脚本正确启动 du-sh 对于每个用户,但随后立即尝试进入下一步,中断。

    那么,我的问题是,为什么我的脚本不等待后台任务完成,以及如何实现这种行为?

    最后,我尝试了其他几种方法从 this SO post ,但也无法让它们工作。

    1 回复  |  直到 3 年前
        1
  •  1
  •   KamilCuk    3 年前
    GetFileSpace ... &
    

    您正在将整个功能作为子功能运行。所以它 immediately tries to move on to the next step PID 未设置,因为它正在子流程中设置。

    不要在后台运行它。

    GetFileSpace ...   # no & on the end.
    

    注意:考虑使用 xargs 或GNU parallel . 脚本局部变量首选小写。引用变量展开式。使用shellcheck检查此类错误。

    work() {
       tmp=$(du -hs "$2")
       echo "$tmp" >> "./${1}_filespace.txt"
    }
    export -f work
    for i in "${directories[@]}"; do
       printf "$i %s\n" /home/${1}/data/*
    done | xargs -n2 -P$(nproc) bash -c 'work "$@"' _
    

    请注意,当作业受I/O限制时,如果在一张光盘上运行多个进程(尤其是没有上限的进程),实际上并没有多大帮助。