bash 拆分文件列表并在每个组上运行命令

bash 拆分文件列表并在每个组上运行命令

我是 bash 和编码的超级初学者,所以请耐心等待。我有一个文件列表(>1000),我需要将它们转换为另一种格式。但是我需要一次对 40 个文件运行该命令。

这是我尝试过的(但它基本上运行命令,因为之前什么都没有, xargs 不起作用)。

path=/home/dir1/dir2/dir3;
ls ${path} >> ${path}/LIST;
FILES=${path}/LIST;
xargs -n 40 <<$FILES | xargs commandname 

答案1

您的问题在于阅读您的列表:

FILES=${path}/LIST;

应该

FILES=$(<"${path}/LIST")

然而,

  • 您也可以xargs直接读取文件:xargs -a "${path}/LIST".
  • xargs您根本不需要重复。
  • 您应该始终双引号您的文件名变量!
  • 如果您的路径包含空格或换行符,您的脚本就会出现很多问题。
  • 添加-rxargs以防止在未找到文件的情况下运行不带参数的命令。

无论如何,

不解析ls

您应该使用数组代替。

另外,最好习惯将\0和 一起用作分隔符,以xargs -0防止换行符作为文件名的一部分出现问题。

shopt -s nullglob # avoid `*` as file if no files found in $path
path=/home/dir1/dir2/dir3
files=("${path}"/*)
printf '%s\0' "${files[@]}" | xargs -0 -r -n40 commandname
shopt -u nullglob

或者使用parallel代替xargs

shopt -s nullglob
parallel -j1 -n40 commandname ::: /home/dir1/dir2/dir3/*

答案2

zsh代替bash.

autoload zargs
zargs -rl40 -- /home/dir1/dir2/dir3/*(nN) -- commandname

n对于numericglobsort排序顺序,通常对于编号文件更好(因此file10要排序 file2对于实例)和Nfor (因此,如果匹配,nullglob则不会抱怨,并且在不包含任何非隐藏文件或不可读时归档))。/home/dir1/dir2/dir3/*/home/dir1/dir2/dir3

答案3

我认为这样的东西可以工作,而不需要使用 GNU 扩展。

set -- # clear positional arguments
for file in /home/dir1/dir2/dir3/*
do
    [ -e "$file" ] || continue
    set -- "$@" "$file"
    if [ "$#" -eq 40 ]
    then
        commandname "$@"
        set --
    fi
done
# in case the number of files is a number not divisible by 40
if [ "$#" -gt 0 ] && [ "$#" -lt 40 ]
then
    commandname "$@"
fi

我不知道命令是什么,但是当我做了一个类似的函数时

commandname()
{
    printf 'received %d arguments\n' "$#"
    printf 'listing received filenames\n'
    counter=0
    for par in "$@"
    do
        counter="$(( counter+1 ))"
        printf 'argument number %d: %s' "$counter" "$par" | LC_ALL=POSIX tr -d '[:cntrl:]'
        printf '\n'              
    done
}

据我所知,它显示了收到的适当数量的邮件,并正确列出了所有邮件。我对此处列出的大多数文件名进行了测试如何测试 shell 脚本的文件处理稳健性?(53 个文件)。

还值得注意的是,这不会找到隐藏文件(以点开头的文件),但您在 OP 中编写的内容也找不到,所以我认为这很好。如果您只需要常规文件,请更改-e "$file" ][ -f "$file" ].

答案4

find /home/dir1/dir2/dir3 -maxdepth 1 -print0 |
  xargs -0 -n 40 -P 0 commandname

请注意,如果文件数不是 40 的倍数,则其中一个commandname进程将无法使用 40 个参数运行。

相关内容