bash - 通过 GNU 并行将 args 传递给定义的 bash 函数
问题描述
让我向您展示我的 Bash 脚本片段以及我如何尝试并行运行:
parallel -a "$file" \
-k \
-j8 \
--block 100M \
--pipepart \
--bar \
--will-cite \
_fix_col_number {} | _unify_null_value {} >> "$OUTPUT_DIR/$new_filename"
因此,我基本上是在尝试使用脚本中定义的 Bash 函数并行处理文件中的每一行。但是,我不确定如何将每一行传递给我定义的函数“_fix_col_number”和“_unify_null_value”。无论我做什么,都不会传递给函数。
我在我的脚本中导出这样的函数:
declare -x NUM_OF_COLUMNS
export -f _fix_col_number
export -f _add_tabs
export -f _unify_null_value
提到的功能是:
_unify_null_value()
{
_string=$(echo "$1" | perl -0777 -pe "s/(?<=\t)\.(?=\s)//g" | \
perl -0777 -pe "s/(?<=\t)NA(?=\s)//g" | \
perl -0777 -pe "s/(?<=\t)No Info(?=\s)//g")
echo "$_string"
}
_add_tabs()
{
_tabs=""
for (( c=1; c<=$1; c++ ))
do
_tabs="$_tabs\t"
done
echo -e "$_tabs"
}
_fix_col_number()
{
line_cols=$(echo "$1" | awk -F"\t" '{ print NF }')
if [[ $line_cols -gt $NUM_OF_COLUMNS ]]; then
new_line=$(echo "$1" | cut -f1-"$NUM_OF_COLUMNS")
echo -e "$new_line\n"
elif [[ $line_cols -lt $NUM_OF_COLUMNS ]]; then
missing_columns=$(( NUM_OF_COLUMNS - line_cols ))
new_line="${1//$'\n'/}$(_add_tabs $missing_columns)"
echo -e "$new_line\n"
else
echo -e "$1"
fi
}
我尝试从并行中删除 {}。不太确定我做错了什么。
解决方案
我在调用中看到两个问题以及函数的其他问题:
--pipepart
没有论据。从中读取的块-a file
通过标准输入传递给您的函数。尝试使用以下命令来确认这一点:
seq 9 > file
parallel -a file --pipepart echo
parallel -a file --pipepart cat
理论上,您可以将 stdin 读入一个变量并将该变量传递给您的函数,
parallel -a file --pipepart 'b=$(cat); someFunction "$b"'
......但我不推荐它,特别是因为您的块是 100MB。- Bash甚至在看到它
|
之前就解释了你的命令中的管道。parallel
要运行管道,请引用整个命令:
parallel ... 'b=$(cat); _fix_col_number "$b" | _unify_null_value "$b"' >> ...
_fix_col_number
似乎假设它的参数是单行,而是接收 100MB 块。_unify_null_value
不读取标准输入,因此_fix_col_number {} | _unify_null_value {}
等价于_unify_null_value {}
.
话虽如此,您的功能可以大大改善。他们启动了很多进程,这对于较大的文件来说变得非常昂贵。你可以做一些微不足道的改进,比如合并perl ... | perl ... | perl ...
成一个perl
. 同样,您可以直接处理标准输入,而不是将所有内容存储在变量中:只需f() { cmd1 | cmd2; }
使用f() { var=$(echo "$1" | cmd1); var=$(echo "$var" | cmd2); echo "$var"; }
.
但是,不要在这些小事上浪费时间。完全重写sed
、awk
或perl
很容易,并且应该优于现有函数的所有优化。
尝试
n="INSERT NUMBER OF COLUMNS HERE"
tabs=$(perl -e "print \"\t\" x $n")
perl -pe "s/\r?\$/$tabs/; s/\t\K(\.|NA|No Info)(?=\s)//g;" file |
cut -f "1-$n"
如果您仍然觉得这太慢,请忽略file
;将命令打包成一个函数,导出该函数,然后调用parallel -a file -k --pipepart nameOfTheFunction
. 该选项--block
不是必需的,因为pipepart
它将根据作业数量平均分配输入(可以使用 指定-j
)。
推荐阅读
- c - 程序返回错误的数字
- c++ - 在游戏引擎布局中使用 shared_ptr?
- r - 绘制 3D 平面和矢量
- html - 无法更改标题中的链接颜色代码
- visual-foxpro - 在字符串中浏览年份
- javascript - 强制 JavaScript setTimout 函数在 x 毫秒后运行
- oauth-2.0 - 是否有任何 OAuth 授权支持代表用户授予访问权限,而无需用户交互?
- laravel - 如何将默认 elqount 分页查询字符串更改为其他页面=?
- laravel - PhpStorm 为相同的方法显示不同的颜色
- javascript - 如何通过单击或悬停在第一个 div 元素旁边水平显示另一个 div 元素?在第一个 div