我需要在 bash 中创建一个循环来垂直连接图像并输出多个连接页面进行打印

我需要在 bash 中创建一个循环来垂直连接图像并输出多个连接页面进行打印

我运行的是 Ubuntu 18.04。我有一个充满故事板图像的目录,.jpg格式如下。

image-0000.jpg
image-0001.jpg
image-0002.jpg
image-0003.jpg
image-0004.jpg
.
.
image-3898.jpg
image-3899.jpg

垂直合并 13 个图像就形成一个页面。所以我想我需要使用下面的命令,在循环中一次使用 13 个数字的范围并保存到目录中"./Merged"

convert -append image-{range of 13}.jpg ./Merged/page_001.jpg

我的实验和思考过程如下。

我正在尝试使用嵌套for循环,seq -w如下所示。但我无法理解,如何以需要前 13 个文件(from image-0000 to image-0012)、合并它们并保存在文件夹中的方式循环脚本./Merged/。然后退出循环并再次获取接下来的 13 个文件(from image-0013 to image-0025),依此类推。直到.jpg当前文件夹中的所有文件完成或生成300页。

我的脚本

#!/bin/bash

# As 3899 image slices will be converted to 300 pages
# I thought to run for loop 300 times

for ((page=1; page<=300; page++))
do
   # As images are slices of pages.
   for slices in $(seq -w 0 3899)
   do

    # We need to merge 13 times so...
    # Should i use for loop with increment as below?
    # for ((smerge=1; smerge<=13; smerge++))
    # do
    #   convert "SOME LOGIC" ./Merged/page_001.jpg
    # done

    # **OR**
    # somehow take 13 numbers from sequence

        convert image-$slices_{RANGE}.jpg -append ./Merged/page_$page.jpg 
        
   done

done

答案1

zsh

#! /bin/zsh -

typeset -Z3 page
files=(image-<0-3900>.jpg)
for ((page = 1; $#files; page++)) {
  convert $files[1,13] -append ./Merged/page_$page.jpg
  files[1,13]=()
}

请注意,由于有 3901 张图像 (13 × 300 + 1),因此最后一页只有一张图像。

你可以做类似的事情bash

#! /bin/bash -
shopt -s extglob
shopt -s failglob
set -- image-+([[:digit:]]).jpg
for ((page = 1; $#; page++)) {
  printf -v padded_page %03d "$page"
  convert "${@:1:13}" -append "./Merged/page_$padded_page.jpg"
  (($# > 13)) || break
  shift 13
}

POSIXly,假设存在匹配的文件并对文件名进行不太严格的检查:

#! /bin/sh -
set -- image-*.jpg

# disable split+glob, only retain empty removal on unquoted expansions:
set -o noglob; IFS=

page=1; while [ "$#" -gt 0 ]; do
  padded_page=000$page
  padded_page=${padded_page#"${padded_page%???}"}
  convert $1 $2 $3 $4 $5 $6 $7 $8 $9 ${10} ${11} ${12} ${13} \
    -append "./Merged/page_$padded_page.jpg"
  [ "$#" -gt 13 ] || break
  shift 13
  page=$((page + 1))
done

请注意,虽然这里的文件名非常简单(没有空格、特殊字符...),但这些代码中特别注意处理任意字符。但请注意,convert其他 imagemagick 实用程序可能会出现以-(即使使用--)或包含 开头的文件名出现问题:,因此最好在文件路径前加上前缀 以./避免这些问题(例如,使用./*.jpg代替*.jpg)。

答案2

假设您的这些文件位于从image-0000.jpg到 的连续范围内image-2999.jpg。这应该展示了这里的工作原理:

#!/bin/bash
for page in {000..001}; do
  echo image-${page}{0..9}.jpg
done

因此,请将其放入您的用例中:

#!/bin/bash
for page in {000..001}; do
  convert image-${page}{0..9}.jpg --append ./Merged/page-${page}.jpg
done

请注意,{01..02}扩展到01 02而不是1 2需要bash4。

答案3

您可以使用xargs -n参数来执行此操作并将结果推入while read循环。

page=1
while IFS= read -r row; do
    convert $row -append ./Merged/page_$page.jpg
    page=$((page + 1))
done < <(echo image-{0000..3900}.jpg | xargs -n13)

答案4

大家好。非常感谢您的时间和回复。

DopeGhoti、菲利普·肯德尔、斯蒂芬·查泽拉斯、RoVo

这就是我能够创造的,并且它有效。 不过我也想检查其他解决方案。也许你的解决方案比我的基本脚本更快。

笔记:如果文件名中有空格,此脚本将/可能会失败!

仅有脚本

#!/bin/bash

# NOTE: This Script will/might fail if there are spaces in file names!

mkdir -p Finished;
mkdir -p Merged;

for paGe in $(seq -w 1 300)
do
   ls *.jpg | head -n 13 > filesData.txt;
   paGeData=$(sed ':a;N;$!ba;s/\n/ /g' filesData.txt);
   convert $paGeData -append ./Merged/Page_$paGe.jpg;

   while read -r line
   do
      mv $line ./Finished/
   done < filesData.txt
done

带注释的脚本

#!/bin/bash

# NOTE: This Script will/might fail if there are spaces in file names!
# I random capitalize letters in a variable to make them unique,
# As i can't be sure.

mkdir -p Finished;
mkdir -p Merged;

for paGe in $(seq -w 1 300)
do
   # Selecting only 13 files from the current directory
   ls *.jpg | head -n 13 > filesData.txt;

   # Replace newline (\n) with space and place "file names"
   # in one line and storing "sed" output to a variable.
   # So that we use it with "convert" command.
   paGeData=$(sed ':a;N;$!ba;s/\n/ /g' filesData.txt);

   # Merge different images to one long image
   convert $paGeData -append ./Merged/Page_$paGe.jpg;

   # Move files to different directory,
   # So that we can work with next range/batch of files.
   while read -r line
   do
      mv $line ./Finished/
   done < filesData.txt

done

一个漫长的思考过程。如果有人可能对我如何尝试即兴编写代码感兴趣。这可能有一些错误。

#!/bin/bash

mkdir -p Finished;
mkdir -p Merged;

for paGe in $(seq -w 1 300)
do

   # Selecting only 13 files from the current directory
   ls *.jpg | head -n 13 > filesData.txt;

   # Replace newline (\n) with space and
   # place file names in one line for the convert command in while loop
#   sed ':a;N;$!ba;s/\n/ /g' filesData.txt > paGeData.txt;
   # We can remove below loop by storing sed (above) output to a variable
   # and substituting it later in the command.
   paGeData=$(sed ':a;N;$!ba;s/\n/ /g' filesData.txt);

   # Merge different images to one long image
   # "line" is a system variable
#   while read -r line
#   do
#      convert $line -append ./Merged/Page_$paGe.jpg
#   done < paGeData.txt
   convert $paGeData -append ./Merged/Page_$paGe.jpg;

   # Move files to different directory,
   # So that we can work with next range/batch of files.
   while read -r line
   do
      mv $line ./Finished/
   done < filesData.txt

done

相关内容