根据总大小附加图像组

根据总大小附加图像组

我有数百张以此模式命名的图像:

file-001.gif
file-002.gif
file-003.gif
...

使用 magick,我想附加每组图像,条件是它们的总大小不超过 950kb。

然后在总大小小于 950kb 时处理下一批,依此类推。

可以在shell脚本中实现吗?

答案1

好吧,我非常有信心这是我遇到过的最糟糕的单线,但我想它会做到这一点。松散地基于https://askubuntu.com/questions/878948/how-do-i-generate-a-running-cumulative-total-of-the-numbers-in-a-text-file

sed $(echo 3+`ls -la | tee out/filesWithSizes.txt | awk '{print $5}' | awk '{total += $0; $0 = total}1' | sed 's/$/ < 950000/' | bc | grep -o '1' | wc -l`|bc )q out/filesWithSizes.txt | tail -n +4

让我解释一下这种疯狂:

用于ls -la获取所有文件及其大小

用于tee存储该信息以供将来参考并将其保存在管道中

用于awk打印第5列(即大小)

使用 moreawk生成其累积和,保证每个设计都已排序(稍后会变得很重要)

用于sed替换行尾,< 950000因此基本上附加该字符串

用于bc计算这些表达式并将它们转换为布尔值(即 0 或 1)

用于grep -o仅打印包含 1 的行

由于累积总和是按设计排序的,因此可以计算其输出,并且您知道可以粘贴在一起的文件数(按顺序)

这部分是用 完成的wc -l。由于我在最初没有 a 标志的情况下无法正常工作,因此ls我回显 3+我们刚刚计算出的数字bc以获取文件列表输出的停止点

然后使用sed命令替换来停止输出文件列表的内容及其大小,这些文件的大小是我们之前用 echo 计算的行数之后保存的

最后用于tail从所述文件的第一个非标题行开始输出。

这将为您提供可以拼接在一起的所有文件的列表。您只需确保移走已处理的所有文件,并一遍又一遍地重新运行该庞大的 oneliner,直到目录中不再有文件为止...

答案2

如果您需要批量附加的图像最终位于小于 950kB 的对象内,则任何单个图像文件都不能超过相同的截止大小。
第一步:列出所有此类文件及其大小(以字节为单位):

$ find -L /path/to/directory -maxdepth 1 -type f -name "*.gif" -size -950k \
 -exec sh -c '\ls -Lgo "$1" | tr -s " "  | cut "-d " -f3,7-' sh {} \;

这将在屏幕上打印所有找到的文件的名称及其各自的大小,一行打印,按找到的顺序列出。主要标志find是:

  • -L:跟随符号链接并显示有关链接目标的信息,而不是有关链接本身的信息。如果您不想这样做,请-H改为使用。
  • -maxdepth 1:使搜索最多下降1水平,从 下降/path/to/directory。根据需要修改号码。请参阅man find获取更多信息。

请注意,至少在我的bash5.0 实现中,find似乎可以使用千字节 (kiB) 来运行。换句话说,上面将找到大小小于或等于 950*1024 字节的文件。如果您坚持将 950 KB (950000 B) 作为您的截止大小,没问题:只需使用-size 927730c即可。在 Debian 发行版上,这个问题似乎早在 2016 年就已经得到解决,所以你可以继续使用-size 950k......

“尺寸”可以是一个不明确的属性。由于OP中缺乏更多信息,我还包括您可以使用的事实总分配块大小对于每个发现的文件。如果这就是您想要/需要的,那么请执行以下操作:

$ find -L /path/to/directory -maxdepth 1 -type f -name "*.gif" -size -950k \
  -exec sh -c '\ls -Ls -C1 "$1"' sh {} \;

您从中获得的大小数字将取决于存储介质的块大小。

第二步magick:通过 shell 脚本batch_append.sh一次性处理先前的输出。按列出的顺序附加图像文件,但结果对象的重量不得超过 950kB。该命令的输出find用于填充数组,如下所示:

$ cat batch_append.sh

#!/usr/bin/bash

sdir=/path/to/directory
size=0
nas_idx=0    # next append start (nas) index (idx)
cnt=0
declare -a b

IFS=$'\n' read -d '' -a a < <(find -L "$sdir" -maxdepth 1 -type f -name "*.gif" -size -950k -exec sh -c '\ls -Lgo "$1" | tr -s " " | cut "-d " -f3,7-' sh {} \; 2>/dev/null)
num=${#a[@]}

for (( i=0; i<num; i++ )); do
    (( size+=$(echo "${a[$i]}" | cut "-d " -f1) ))

    if [ "$size" -gt 950000 ] ; then
        (( size-=$(echo "${a[$i]}" | cut "-d " -f1) ))
        (( i-=1 ))
        #echo "$size" for files from "$(( nas_idx+1 ))" to "$(( i+1 ))"  # testing
        #echo "${b[@]}"   # testing
        magick "${b[@]}" append appended_$(( nas_idx+1 ))_$(( i+1 )).gif
        nas_idx=$(( i+1 ))
        size=0  # reset 'size' variable to start new append batch
        cnt=0
        unset b
    else
        b[cnt]=$(echo "${a[$i]}" | cut "-d " -f2-)
        (( cnt++ ))
    fi

    if (( i==num-1 )); then
        # last append batch
        #echo "$size" for files from "$(( nas_idx+1 ))" to "$(( i+1 ))"  # testing
        #echo "${b[@]}"   # testing
        magick "${b[@]}" append appended_$(( nas_idx+1 ))_$(( i+1 )).gif
        unset b
    fi
done

printf '\n  %d files were processed.\n' "$num"
exit(0)

结束语:

  • 在运行脚本之前使脚本可执行。chmod ug+x batch_append.sh
  • 您只需运行该脚本一次。
  • 该脚本尚未经过magick.
  • 对于生产环境,应该包含许多陷阱。
  • 如果您的主机有多个内核并且需要处理大量文件,则可以改进脚本,也许可以通过安排并行执行来改进。
  • 文件在到来时即被批处理,即当findcmd 对它们进行统计时。这将取决于搜索标志的数量以及您在一行中的排序方式find

相关内容