写入文件时Bash并发性

写入文件时Bash并发性,bash,Bash,我想对一长串的项目子集运行一个脚本,并且每个项目都并发运行,只有在每次迭代完成后,才将其写入一个文件 出于某种原因,它在未完成函数的情况下写入文件: #!/bin/bash function print_not_semver_line() { echo -n "$repo_name," git tag -l | while read -r tag_name;do semver $tag_name > /dev/null || echo -n "$tag_n

我想对一长串的项目子集运行一个脚本,并且每个项目都并发运行,只有在每次迭代完成后,才将其写入一个文件

出于某种原因,它在未完成函数的情况下写入文件:

#!/bin/bash

function print_not_semver_line() {
    echo -n "$repo_name,"
    git tag -l | while read -r tag_name;do
        semver $tag_name > /dev/null || echo -n "$tag_name "
    done
    echo ""
}
csv_name=~/Scripts/all_repos/not_semver.csv
echo "Repo Name,Not Semver Versions" > $csv_name
while read -r repo_name;do
    cd $repo_dir
    print_not_semver_line >> $csv_name &    
done < ~/Scripts/all_repos/all_repos.txt
#/bin/bash
函数打印\u非\u符号\u行(){
echo-n“$repo_名称,”
git标记-l |而read-r标记-u name;do
semver$tag_name>/dev/null | | echo-n“$tag_name”
完成
回声“”
}
csv\u name=~/Scripts/all\u repos/not\u semver.csv
echo“回购名称,非Semver版本”>$csv\u名称
读取时-r repo_名称;做
cd$repo_dir
打印“\u not\u semver\u line>>$csv\u name&
完成<~/Scripts/all\u repos/all\u repos.txt
当然,如果没有
&
,它会做它应该做的事情,但是有了它,一切都变得一团糟


想法?

这里有一个替代方案,它使用
xargs
实现自然并行化,还有一个快速脚本,用于确定repo结束时的所有非semver标记和输出

前提是这个脚本不做任何花哨的事情,它只是在它提供的目录上循环,一次只做一个,您可以在脚本之外并行化

#/bin/bash
日志(){
现在=$(日期-Isec--utc)
echo“${now}$$$${*}”>/dev/stderr
}
#我没有其他可用的semver,所以需要一个仿制品替代品
函数为_semver(){
回声“$*”| egrep-q“^v?[0-9]+\[0-9]+\[0-9]+\[0-9]+$”
}
日志“使用:${@}调用”
对于${@}中的repo_dir;做
日志“正在启动“${repo_dir}”
坏的=$(
git-C“${repo_dir}”标记-l|\
在读取标签名称时,执行以下操作:
是“${tag_name}”| | echo-n“${tag_name}”
完成
)
日志“完成${repo_dir}”
回显“${repo_dir},${bad}”
完成
日志“正在退出”
我有一个包含各种克隆github repo的项目目录,我将在这里使用
xargs
运行它。请注意以下几点:

  • 我正在演示如何使用
    -L2
    每次调用两个目录(未并行化)调用脚本,但是
    -P4
    其中四个脚本同时运行
  • 管道中剩余的
    xargs
    应该是您确定要迭代的dirs/repos的方法
  • 第一批流程从PIDs 17438、17439、17440和17442开始,并且仅当其中一个退出(17442和17439)是新流程开始时
  • 如果您不担心同时运行太多的东西,那么可以使用
    xargs-L1-P9999
    或其他同样荒谬的工具:-)
$find-maxdepth 2-iname.git | sed-e's,/\.git,,g'| head-n12 |\
xargs-L2-P4~/StackOverflow/5783481/62283574_2.sh>not_semver.csv
2020-06-09T17:51:39+00:00 17438呼叫者:./calendar./callr
2020-06-09T17:51:39+00:00 17439呼叫时使用:./docker自助服务密码。/ggnomics
2020-06-09T17:51:39+00:0017438开始“/日历”
2020-06-09T17:51:39+00:00 17440调用时使用:./ggplot2./grid
2020-06-09T17:51:39+00:00 17439开始“/docker自助密码”
2020-06-09T17:51:39+00:00 17442呼叫时使用:./gt./keyring
2020-06-09T17:51:39+00:0017440开始“/ggplot2”
2020-06-09T17:51:39+00:0017442开始。'/gt'
2020-06-09T17:51:39+00:0017442完成。'/gt'
2020-06-09T17:51:40+00:0017442启动“/钥匙圈”
2020-06-09T17:51:40+00:0017438完成。'/日历'
2020-06-09T17:51:40+00:0017438开始“/callr”
2020-06-09T17:51:40+00:00 17439完成。'/docker自助服务密码'
2020-06-09T17:51:40+00:0017439开始“/ggnomics”
2020-06-09T17:51:40+00:0017442完成。'/keyring'
2020-06-09T17:51:40+00:0017439完成。“/ggnomics”
2020-06-09T17:51:40+00:0017442退出
2020-06-09T17:51:40+00:0017439退出
2020-06-09T17:51:40+00:0017515呼叫时使用:./knitr./ksql
2020-06-09T17:51:40+00:0017518调用:./nanodbc./nostalgy
2020-06-09T17:51:40+00:0017515开始“/knitr”
2020-06-09T17:51:40+00:0017518开始“/nanodbc”
2020-06-09T17:51:41+00:0017438完成。'/callr'
2020-06-09T17:51:41+00:0017438退出
2020-06-09T17:51:42+00:0017440完成。/ggplot2'
2020-06-09T17:51:42+00:0017440开始“/电网”
2020-06-09T17:51:43+00:0017518完成。'/nanodbc'
2020-06-09T17:51:43+00:0017518开始“/nostalgy”
2020-06-09T17:51:43+00:0017518完成。'/nostalgy'
2020-06-09T17:51:43+00:0017518退出
2020-06-09T17:51:43+00:0017440完成。'/grid'
2020-06-09T17:51:43+00:0017440退出
2020-06-09T17:51:44+00:0017515完成。'/knitr'
2020-06-09T17:51:44+00:0017515开始“/ksql”
2020-06-09T17:51:55+00:0017515完成。'/ksql'
2020-06-09T17:51:55+00:0017515退出
输出,在
not_semver.csv
中:

./gt,
./calendar,
./docker-self-service-password,2.7 2.8 3.0
./keyring,
./ggnomics,
./callr,
./ggplot2,ggplot2-0.7 ggplot2-0.8 ggplot2-0.8.1 ggplot2-0.8.2 ggplot2-0.8.3 ggplot2-0.8.5 ggplot2-0.8.6 ggplot2-0.8.7 ggplot2-0.8.8 ggplot2-0.8.9 ggplot2-0.9.0 ggplot2-0.9.1 ggplot2-0.9.2 ggplot2-0.9.2.1 ggplot2-0.9.3 ggplot2-0.9.3.1 show
./nanodbc,
./nostalgy,
./grid,0.1 0.2 0.5 0.5-1 0.6 0.6-1 0.7-1 0.7-2 0.7-3 0.7-4
./knitr,doc v0.1 v0.2 v0.3 v0.4 v0.5 v0.6 v0.7 v0.8 v0.9 v1.0 v1.1 v1.10 v1.11 v1.12 v1.13 v1.14 v1.15 v1.16 v1.17 v1.18 v1.19 v1.2 v1.20 v1.3 v1.4 v1.5 v1.6 v1.7 v1.8 v1.9
./ksql,0.1-pre1 0.1-pre10 0.1-pre2 0.1-pre4 0.1-pre5 0.1-pre6 0.1-pre7 0.1-pre8 0.1-pre9 0.3 v0.2 v0.2-rc0 v0.2-rc1 v0.3 v0.3-rc0 v0.3-rc1 v0.3-rc2 v0.3-rc3 v0.3-temp v0.4 v0.4-rc0 v0.4-rc1 v0.5 v0.5-rc0 v0.5-rc1 v4.1.0-rc1 v4.1.0-rc2 v4.1.0-rc3 v4.1.0-rc4 v4.1.1-rc1 v4.1.1-rc2 v4.1.1-rc3 v4.1.2-beta180719000536 v4.1.2-beta3 v4.1.2-rc1 v4.1.3-beta180814192459 v4.1.3-beta180828173526 v5.0.0-beta1 v5.0.0-beta10 v5.0.0-beta11 v5.0.0-beta12 v5.0.0-beta14 v5.0.0-beta15 v5.0.0-beta16 v5.0.0-beta17 v5.0.0-beta18 v5.0.0-beta180622225242 v5.0.0-beta180626015140 v5.0.0-beta180627203620 v5.0.0-beta180628184550 v5.0.0-beta180628221539 v5.0.0-beta180629053850 v5.0.0-beta180630224559 v5.0.0-beta180701010229 v5.0.0-beta180701053749 v5.0.0-beta180701175910 v5.0.0-beta180701205239 v5.0.0-beta180702185100 v5.0.0-beta180702222458 v5.0.0-beta180706202823 v5.0.0-beta180707005130 v5.0.0-beta180707072142 v5.0.0-beta180718203558 v5.0.0-beta180722214927 v5.0.0-beta180723195256 v5.0.0-beta180726003306 v5.0.0-beta180730183336 v5.0.0-beta19 v5.0.0-beta2 v5.0.0-beta20 v5.0.0-beta21 v5.0.0-beta22 v5.0.0-beta23 v5.0.0-beta24 v5.0.0-beta25 v5.0.0-beta26 v5.0.0-beta27 v5.0.0-beta28 v5.0.0-beta29 v5.0.0-beta3 v5.0.0-beta30 v5.0.0-beta31 v5.0.0-beta32 v5.0.0-beta33 v5.0.0-beta5 v5.0.0-beta6 v5.0.0-beta7 v5.0.0-beta8 v5.0.0-beta9 v5.0.0-rc1 v5.0.0-rc3 v5.0.0-rc4 v5.0.1-beta180802235906 v5.0.1-beta180812233236 v5.0.1-beta180824214627 v5.0.1-beta180826190446 v5.0.1-beta180828173436 v5.0.1-beta180830182727 v5.0.1-beta180902210116 v5.0.1-beta180905054336 v5.0.1-beta180909000146 v5.0.1-beta180909000436 v5.0.1-beta180911213156 v5.0.1-beta180913003126 v5.0.1-beta180914024526 v5.0.1-beta181008233543 v5.0.1-beta181018200736 v5.0.1-rc1 v5.0.1-rc2 v5.0.1-rc3 v5.0.2-beta181116204629 v5.0.2-beta181116204811 v5.0.2-beta181116205152 v5.0.2-beta181117022246 v5.0.2-beta181118024524 v5.0.2-beta181119063215 v5.0.2-beta181119185816 v5.0.2-beta181126211008 v5.1.0-beta180611231144 v5.1.0-beta180612043613 v5.1.0-beta180612224009 v5.1.0-beta180613013021 v5.1.0-beta180614233101 v5.1.0-beta180615005408 v5.1.0-beta180618191747 v5.1.0-beta180618214711 v5.1.0-beta180618223247 v5.1.0-beta180618225004 v5.1.0-beta180619025141 v5.1.0-beta180620180431 v5.1.0-beta180620180739 v5.1.0-beta180620183559 v5.1.0-beta180622181348 v5.1.0-beta180626014959 v5.1.0-beta180627203509 v5.1.0-beta180628064520 v5.1.0-beta180628184841 v5.1.0-beta180630224439 v5.1.0-beta180701010040 v5.1.0-beta180701175749 v5.1.0-beta180702063039 v5.1.0-beta180702063440 v5.1.0-beta180702214311 v5.1.0-beta180702220040 v5.1.0-beta180703024529 v5.1.0-beta180706202701 v5.1.0-beta180707004950 v5.1.0-beta180718203536 v5.1.0-beta180722215127 v5.1.0-beta180723023347 v5.1.0-beta180723173636 v5.1.0-beta180724024536 v5.1.0-beta180730185716 v5.1.0-beta180812233046 v5.1.0-beta180820223106 v5.1.0-beta180824214446 v5.1.0-beta180828022857 v5.1.0-beta180828173516 v5.1.0-beta180829024526 v5.1.0-beta180905054157 v5.1.0-beta180911213206 v5.1.0-beta180912202326 v5.1.0-beta180917172706 v5.1.0-beta180919183606 v5.1.0-beta180928000756 v5.1.0-beta180929024526 v5.1.0-beta201806191956 v5.1.0-beta201806200051 v5.1.0-beta34 v5.1.0-beta35 v5.1.0-beta36 v5.1.0-beta37 v5.1.0-beta38 v5.1.0-beta39 v5.1.0-rc1 v6.0.0-beta181009070836 v6.0.0-beta181009071126 v6.0.0-beta181009071136 v6.0.0-beta181011024526
为了减少冗长,您可以删除
log
ging等等,这些输出的大部分都是为了演示计时和运行


作为另一种选择,考虑这样的事情:

log(){
现在=$(日期-Isec--utc)
echo“${now}${*}”>/dev/stderr
}
#我没有其他可用的semver,所以需要一个仿制品替代品
函数为_semver(){
回声“$*”| egrep-q“^v?[0-9]+\[0-9]+\[0-9]+\[0-9]+$”
}
函数print_something(){
本地回购名称=$1标签名称=
坏的=$(
git tag-l |读取tag_name;do
是“${tag_name}”| | echo-n“${tag_name}”
完成
)
回显“${repo_name},${bad}”
}
csvdir=$(mktemp-d not_semver_tempdir.XXXXXX)
csvdir=$(实路径“${csvdir}”)/
日志“临时目录:${csvdir}”
而read-r repo_dir;做
日志“正在启动“${repo_dir}”
(
如果[-d“${repo_dir}”];则
repo_name=$(basename“${repo_dir}”)
tmpfile=$(mktemp-p“${csvdir}”)
tmpfile=$(realpath“${tmpfile}”)
cd“${repo_dir}”
打印内容“${repo\u name}”>“${tmpfile}”2>/dev/null
fi
) &
完成
等待
outfile=$(mktemp非\u semver\uxxxxxx.csv)
cat${csvdir}*>“${outfile}”
#rm-rf“${csvdir}”#在您感到舒适/自信时取消注释
日志“输出:${outfile}”
我不太喜欢它
#!/bin/bash

print_not_semver_line() {
    # random file name for line buffering
    local tmpfile="${0%.*}${!:-0}.tmp~"
    touch "$tmpfile" || return 1

    # redirect stdout into different tmp file
    echo -n "$repo_name," > "$tmpfile"
    git tag -l | while read -r tag_name;do
        semver $tag_name > /dev/null || echo -n "$tag_name " >> "$tmpfile"
    done
    echo "" >> "$tmpfile"

    # print the whole line from one single ride
    cat "$tmpfile" && rm "$tmpfile" && return 0
}
# wait for open files (of)
wait_of() {
    local pattern="$1" limit=${2:-4} time=${3:-1} path of

    # check path
    path="${pattern%/*}"
    pattern="${pattern##*/}"
    [ "$path" = "$pattern" ] && path=.
    [ -e "$path" ] && [ -d "$(realpath "$path")" ] || return 1

    # convert file name into regex
    pattern="${pattern//[0-9]/0}"
    while [[ "$pattern" =~ "00" ]]
      do
        pattern="${pattern//00/0}"
    done
    pattern="${pattern//0/[0-9]*}"
    pattern="${pattern//[[:space:]]/[[:space:]]}"

    # check path with regex for open files > 4 and wait
    of=$(lsof -t "$path"/$pattern 2> /dev/null | wc -l)
    while (( ${of:-0} > $limit ))
      do
        of=$(lsof -t "$path"/$pattern 2> /dev/null | wc -l)
        sleep $time
    done

    return 0
}

# make sure only give one single tmp file name
wait_of "${0%.*}${!:-0}.tmp~" || exit 2
print_not_semver_line >> $csv_name &