AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题

问题[gnu-parallel](unix)

Martin Hope
JSQuareD
Asked: 2025-04-26 12:25:40 +0800 CST

如何使 GNU 并行以适合在终端外使用的方式报告进度?

  • 6

我想在 Github CI 工作流(在 Ubuntu 运行器上)中对一组文件并行运行一个命令,以加快 CI 作业的速度。我还希望并行命令能够报告其进度。

目前我的命令看起来像这样:

# ci/clang-tidy-parallel.sh
find src \
  ! -path "path/to/exclude/*" \
  -type f \( -name "*.cpp" -o -name "*.h" \) \
  | parallel --progress "clang-tidy-19 {}"

当从我自己的机器上的 shell 运行时,它工作得很好:作业并行执行,并且显示一行输出,其中显示正在进行的作业数以及已经完成的作业数。

然而,当作为 Github 工作流的一部分运行时,输出有点令人讨厌:

  1. sh: 1: cannot open /dev/tty: No such device or address它会多次打印该错误。
  2. 它打印的进度输出远远超出了实际需要。大约有 1700 行进度报告,而实际要运行的作业只有大约 80 个。这些行大部分都是重复的。例如,前几行是:
local:4/0/100%/0.0s 
local:4/0/100%/0.0s 
local:4/0/100%/0.0s 
local:4/0/100%/0.0s 
local:4/0/100%/0.0s 
local:4/0/100%/0.0s 
local:4/0/100%/0.0s 
local:4/0/100%/0.0s 
local:4/0/100%/0.0s 
local:4/0/100%/0.0s 
local:4/0/100%/0.0s 
local:4/0/100%/0.0s 
local:4/0/100%/0.0s 
local:4/0/100%/0.0s 

如果我在本地运行该命令并将 stderr 重定向到文件,我会观察到类似的行为

ci/clang-tidy-parallel.sh 2>log

命令完成后,日志文件包含数百行输出。(虽然没有关于缺少 /dev/tty 的错误。)

另一方面,如果没有该--progress选项,作业就只是停留在那里,没有可见的输出,直到完成为止,这也是不可取的。

有没有办法配置 GNU Parallel,让它以一种对非终端环境友好的方式报告进度?具体来说,我希望它只在并行作业的状态发生变化时打印一行输出(如果一切顺利,这意味着每个作业只打印一行)。


感谢 Ole Tange 为我指明了方向。基于他的解决方案和一些 AI 辅助编码,我设计出了这个怪异的方案:

file_list=$(find src \
  ! -path "path/to/exclude/*" \
  -type f \( -name "*.cpp" -o -name "*.h" \))

length=$(wc -w <<< "$file_list")
echo Running clang-tidy on $length files

echo "$file_list" |
  parallel --bar "clang-tidy-19 {}" \
  2> >(
    perl -pe 'BEGIN{$/="\r";$|=1};s/\r/\n/g' |
    grep '%' |
    perl -pe 'BEGIN{$|=1}s/\e\[[0-9;]*[a-zA-Z]//g' |
    perl -pe "BEGIN{\$length=$length;$|=1} s|(\d+)% (\d+):\d+=[\ds]+ (\S+).*|\$1% (\$2/\$length) -- \$3|" |
    perl -ne '$s{$_}++ or print')

原始输出--bar看起来像这样:

#   0 sec src/tuner/Utilities.h                                                                                                                                         
3.65853658536585
[7m3% 3:7[0m9=0s src/tuner/Utilities.h                                                                                                                                        [0m

(使用转义序列来打印进度条。)

输出的连续命令处理执行以下转换:

  • 将回车符转换为换行符。
  • 查找包含百分比输出的行。
  • 删除转义序列。
  • 执行正则表达式替换,提取并格式化已处理的文件数量、完成百分比以及正在处理的文件的名称。它还包含通过 shell 变量需要处理的文件总数。
  • 打印独特的线条。

除了最后一次 perl 调用之外,所有BEGIN{$|=1}调用都是必要的,以确保输出立即被刷新。

该p选项将在输入的每一行上运行 perl 并打印结果。该n选项在输入的每一行上运行 put 不会自动打印结果。该e选项将脚本作为 CLI 参数提供。

它生成类似如下的输出:

Running clang-tidy on 82 files
1% (1/82) -- src/tuner/LoadPositions.h
2% (2/82) -- src/tuner/Main.cpp
2% (2/82) -- src/tuner/Utilities.h
3% (3/82) -- src/tuner/Utilities.h
...

我确信有更好的方法来执行这些 perl 脚本(而不是写 4 个)。但是这个方法可行,而且我的 perl-foo 很弱。

gnu-parallel
  • 1 个回答
  • 21 Views
Martin Hope
intelfx
Asked: 2025-03-16 01:21:01 +0800 CST

GNU parallel:根据参数值替换字符串或不替换任何内容

  • 7

我正在尝试使用 GNU parallel 来针对几个行为改变标志的所有组合运行命令:

parallel 'cmd --foo {1} --bar {2} {3} out.foo={1}.bar={2}/{3/}' ::: 0 1 ::: 0 1 ::: in/*

这应该会产生一系列类似这样的调用:

cmd --foo 0 --bar 1 'in/fileXYZ' 'out.foo=0.bar=1/fileXYZ'
cmd --foo 1 --bar 0 'in/fileXYZ' 'out.foo=1.bar=0/fileXYZ'

但是,此工具的 CLI 不规则:--foo接受布尔参数,--bar而不接受参数(并且也没有否定形式)。因此,调用必须如下所示:

cmd --foo 0 --bar 'in/fileXYZ' 'out.foo=0.bar=1/fileXYZ'
cmd --foo 1       'in/fileXYZ' 'out.foo=1.bar=0/fileXYZ'

1在 GNU parallel 中将或 的参数转换为命令行上的 的0存在或不存在的最佳(最不冗长)方法是什么?--bar

gnu-parallel
  • 1 个回答
  • 35 Views
Martin Hope
elbarna
Asked: 2024-02-19 07:20:13 +0800 CST

gnu并行:如何控制程序的输出?

  • 5

快速而简单。这个命令有效

locate -i mymovieormysong|parallel mplayer

歌曲(或电影)播放,但我无法用键盘控制 mplayer。如何做到这一点(如果可能的话)?

实际上,当我使用键盘前进或后退时,我得到了这个

^[[C^[[C^[[C^[[C^[[C^[[C^[[C^[[D^[[D^[[D

Edit1:使用 -u (取消分组)选项,输出出现,但当我按下键盘控制 mplayer 时仍然出现 [C 和 [D

gnu-parallel
  • 1 个回答
  • 19 Views
Martin Hope
Iain Samuel McLean Elder
Asked: 2023-12-14 06:22:57 +0800 CST

我可以使用 GNU Parallel 按列值对命令参数进行分组吗?

  • 7

考虑GNU 并行手册示例中的数据--group-by:

cat > table.csv <<"EOF"
UserID, Consumption
123,    1
123,    2
12-3,   1
221,    3
221,    1
2/21,   5
EOF

有没有一种方法可以按一列对记录进行分组,并将组中另一列的所有值作为命令行参数写入?

该命令不会分组,但会提供我想要的输出结构。

cat table.csv | parallel --colsep , --header : -kN1 echo UserID {1}  Consumption {2}
UserID 123 Consumption 1
UserID 123 Consumption 2
UserID 12-3 Consumption 1
UserID 221 Consumption 3
UserID 221 Consumption 1
UserID 2/21 Consumption 5

什么命令会给我这样的输出?

UserID 123 Consumption 1 2
UserID 12-3 Consumption 1
UserID 221 Consumption 3 1
UserID 2/21 Consumption 5

我还想限制“消耗”值的数量。

假设其中一组有超过 4 个人。

cat > table.csv <<"EOF"
UserID, Consumption
123,    1
123,    2
123,    3
123,    4
123,    5
123,    6
123,    7
12-3,   1
221,    3
221,    1
2/21,   5
EOF

我希望命令行包含不超过 4 个“消耗”值。

UserID 123 Consumption 1 2 3 4
UserID 123 Consumption 5 6 7
UserID 12-3 Consumption 1
UserID 221 Consumption 3 1
UserID 2/21 Consumption 5

该手册展示了如何使用--group-by来选择正确的组。

cat table.csv | \
parallel --pipe --colsep , --header : --group-by UserID -kN1 wc

4 行wc输出意味着它对 4 组进行操作。例如,第一组有 3 行、6 个单词和 40 个字符。

      3       6      40
      2       4      30
      3       6      40
      2       4      30

为了使组输入更清晰,我交换wc为cat.

cat table.csv | \
parallel --pipe --colsep , --header : --group-by UserID -kN1 cat

cat 输出显示并行将原始输入行传递给作业并将标题行复制为每个组的第一行。

UserID, Consumption
123,    1
123,    2
UserID, Consumption
12-3,   1
UserID, Consumption
221,    3
221,    1
UserID, Consumption
2/21,   5

问题是--group-by使 Parallel 使用标准输入而不是命令行参数。我看不出有什么办法可以解决这个问题。

我是否需要更改将参数传递给 GNU Parallel 的方式?在使用 GNU 并行执行之前,我是否需要使用其他工具来创建正确的格式?

我正在使用 GNU 并行版本 20231122。

gnu-parallel
  • 1 个回答
  • 37 Views
Martin Hope
intelfx
Asked: 2023-12-05 02:21:36 +0800 CST

使用 GNU Parallel 中的每个输入参数作为工作目录

  • 6

我尝试使用 GNU Parallel 为每个输入参数运行命令,使用该参数作为命令的工作目录(不将其附加到命令行)。

基本上,我需要做的是:

/foo -> "cd /foo; mycmd"
/bar -> "cd /bar; mycmd"
/baz -> "cd /baz; mycmd"

Parallel has--workdir似乎可以通过支持{}替换字符串来实现我想要的功能:

--workdir mydir
--wd mydir

作业将在目录 mydir 中运行。默认值是本地计算机的当前目录,以及远程计算机的登录目录。
<...>
mydir 可以包含 GNU Parallel 的替换字符串。

为了防止参数被附加到命令行,我尝试使用-n0or -N0:

--max-args 最大参数
-n 最大参数

每个命令行最多使用 max-args 个参数。
<...>
-n 0 表示读取一个参数,但在命令行上插入 0 个参数。

然而,这似乎不起作用:

$ mkdir -p $HOME/{foo,bar,baz}
$ printf '%s\n' $HOME/{foo,bar,baz} | parallel --workdir '{}' -n0 'pwd'
parallel: Error: Cannot change into non-executable dir : No such file or directory

请注意 之前的空格:,这不是 GNU 并行中的拼写错误,而是表明 workdir 被评估为空字符串。如果我在 前面添加一个固定字符串{},这一点就会变得很明显,在这种情况下,所有 pwd 都会打印该固定字符串:

$ printf '%s\n' $HOME/{foo,bar,baz} | parallel --workdir '/{}' -N0 'pwd'       
/
/
/

我究竟做错了什么?

gnu-parallel
  • 2 个回答
  • 47 Views
Martin Hope
Ketan Maheshwari
Asked: 2023-08-02 22:14:54 +0800 CST

GNU Parallel:在部分文件可用时运行并等待其余文件

  • 6

我有一个像这样的过程,它会以随机间隔生成预定义数量的文件:

#!/bin/bash

for i in {1..10}
do
  sleep $(shuf -i 20-60 -n 1)
  echo $i > file_$i.txt
done

我有另一个进程,使用 GNU Parallel 独立运行在每个文件上,如下所示:

parallel wc -l ::: file_{1..10}.txt

正如预期的那样,并行在当前可用的文件上运行。有没有办法让并行等待剩余文件可用并尽快运行?

gnu-parallel
  • 2 个回答
  • 45 Views
Martin Hope
Nickotine
Asked: 2023-06-24 02:37:46 +0800 CST

无法使用并行附加到数组

  • 5

当我使用 时,我无法追加到数组parallel,使用 for 循环没有问题。

并行示例:

append() { arr+=("$1"); } 
export -f append

parallel -j 0 append ::: {1..4}
declare -p arr

输出:

-bash: declare: arr: not found

对于循环:

for i in {1..4}; do arr+=("$i"); done
declare -p arr

输出:

declare -a arr=([0]="1" [1]="2" [2]="3" [3]="4")

我认为第一个示例是函数式风格的 for 循环的翻译,那么这是怎么回事呢?

gnu-parallel
  • 2 个回答
  • 26 Views
Martin Hope
Larry
Asked: 2023-05-28 02:10:36 +0800 CST

并联并联

  • 6

我正在尝试并行并行运行,似乎我遇到了一种理想的解决方案。

我想连续运行一组作业——称它们为 A-1、A-2、A-3 等等。这些将与 --jobs 1(或 sem?)一起运行。

我想并行运行这些集合——称它们为 A、B、C 等等。这些将以默认数量的作业(核心)运行。

“A”组作业中的作业数量可能与“B”组作业中的作业数量不同;C或其他类似。

从视觉上看,横轴是时间,纵轴是作业集:

A-1--->A-2--->A-3--->
B-1->B-2-->B-3-->B-4--->
C-1-------------C-2--->
D-1------------------>

为此,我们假设所有作业都处于睡眠状态 $((RANDOM % 10))。

我假设工作集和工作之间必须有某种联系(ala --link)——A 有 1、2 和 3;B 有 1、2、3 和 4;C 有 1 和 2;和 D 只有 1,使用上面的视觉效果。


这可能是我尝试做的更好的例子,使用@ole-tang 的解决方案

$ declare -fp apples bananas cherries dates
apples () 
{ 
    echo -n grannysmith fiji pinklady | parallel -d' ' -j1 'echo apples-{#}: {};sleep $((RANDOM % 3))'
}
declare -fx apples
bananas () 
{ 
    echo -n plantain cavadish red manzano | parallel -d' ' -j1 'echo bananas-{#}: {};sleep $((RANDOM % 3))'
}
declare -fx bananas
cherries () 
{ 
    echo -n sweet sour red yellow bing | parallel -d' ' -j1 'echo cherries-{#}: {};sleep $((RANDOM % 3))'
}
declare -fx cherries
dates () 
{ 
    echo -n medjool khola | parallel -d' ' -j1 'echo dates-{#}: {};sleep $((RANDOM % 3))'
}
declare -fx dates
$ parallel ::: apples bananas cherries dates
bananas-1: plantain
bananas-2: cavadish
bananas-3: red
bananas-4: manzano
dates-1: medjool
dates-2: khola
apples-1: grannysmith
apples-2: fiji
apples-3: pinklady
cherries-1: sweet
cherries-2: sour
cherries-3: red
cherries-4: yellow
cherries-5: bing
gnu-parallel
  • 1 个回答
  • 42 Views
Martin Hope
Dommondke
Asked: 2022-06-29 14:02:22 +0800 CST

管道到 GNU 并行时去除前导和尾随空格

  • 1

当我尝试编写这样的管道时:

git branch | rg '^\*' | parallel git pull {}

我遇到了空格问题。因为分支名称有前导空格,所以并行最终会尝试运行git pull ' foo'这是错误的。

GNU Parallel 是否有一个说法是“去除尾随/前导空格”?或者,是否有一个单独的程序可以做到这一点?

我知道我可以:

  • 使用cut -c 3-,但这仅在前导空格一致的情况下才有效
  • 使用sedor awk,但这些导致每次都必须输入复杂的表达式
pipe gnu-parallel
  • 1 个回答
  • 29 Views
Martin Hope
Henrik supports the community
Asked: 2022-03-16 04:01:19 +0800 CST

在执行命令列表时添加到

  • 2

我正在编译一个庞大的命令列表(所有命令都执行相同的操作),但由于编译该列表需要很长时间,我希望在完成之前开始执行(每个命令的执行通常需要比创建另一个更长的时间,所以没有真正的列表枯竭的风险)。

执行命令列表的正常方法是编写一个列出命令的 shell 脚本,但是当我开始执行脚本时,我不能再添加它了。

到目前为止我发现的方法是将命令放入command.list并拥有parallel --jobs 1 --line-buffer :::: command.list,但由于它涉及使用parallel(我正在使用 GNU 并行,我不知道它是否可以与 more-utils 中的程序一起使用)用于非并行执行事物,我认为这有点滥用parallel.

有没有更简单的方法呢?如果我搞砸了某些事情并且列表确实用完了,那么可以跟踪哪些命令已被执行,这会很好。

shell-script gnu-parallel
  • 1 个回答
  • 71 Views

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    模块 i915 可能缺少固件 /lib/firmware/i915/*

    • 3 个回答
  • Marko Smith

    无法获取 jessie backports 存储库

    • 4 个回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    user12345 无法获取 jessie backports 存储库 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl 为什么大多数 systemd 示例都包含 WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve