我运行的是 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
需要bash
4。
答案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