在一个目录中,我有几个 PNG 和一个文本文件。 PNG 以 UPC 条形码命名,如052100029962.png
、052100045535.png
等,我有一个文本文件upcs.txt
,其中每一行包含与产品名称合并的 UPC 代码,如下所示:
...
052100029962mccormickpepper
052100045535mccormickonesheet
...
我想将每个*.png*
文件重命名为它的产品名称,不带 UPC 编号,使用与文本文件中的字符串匹配的当前文件名 — 所以052100029962.png
我不会使用mccormickkeeper.png
.这出人意料地困难。我尝试过以下各种方法但没有成功。
for f in $(find . -iname "*.png"); do
while read -r line; do
if [[ "$f" == *"$line"* ]]; then ## also tried =~
cp "$f" "$line";
fi
done < upcs.txt
done
我所说的“品种”是指切换操作顺序,例如,将循环放在循环while
之前for
,甚至创建另一个仅包含产品名称的文本文件,以便我read
也可以对它们进行比较。对于后者,我做了:
for f in $(find . -iname "*.png"); do
while read -r line; do
if [[ "$f" == *"$line"* ]]; do
while read -r line2; do
cp "$f" "$line2";
done < upcs_names_only.txt;
fi;
done < upcs.txt;
done
while
我什至尝试在调用循环之前放置第二个循环if
。
最后,我知道即使公式正确,上述循环也会不是保留.png
扩展名。为了解决这个问题,我准备手动选择结果并添加.png
.
我究竟做错了什么?谁能帮助我更好地理解逻辑?
答案1
对于每行包含两个字段的文件,您必须使用分隔符。这里 ased
插入这个分隔符,结果逐行给出mv
#!/bin/bash
while read -r oldname newname; do
[ -f "${oldname}.png" ] && echo mv -- "${oldname}.png" "${newname}.png"
done < <(sed 's/^[0-9]*/& /' upcs.txt)
echo
测试后移除。当然,我假设您的第一个字段始终是数字序列,第二个字段没有空格,不以数字开头等。
如果您需要任何其他操作,例如检查重复的目标名称,您可以首先在文件上执行此操作。或者,如果您需要在任何情况下mv
都不覆盖现有目标,请使用-n
( --no-clobber
),同样-i
( --interactive
) 也会出于同样的原因提示用户输入。
答案2
在您的脚本中, $f var 将是 052100029962.png ,它与 upcs.txt 中的任何行都不匹配:
052100029962.png doesn't match *052100029962mccormickpepper*
假设 UPC 编号始终为 12 个字符长或者产品名称不以数字开头,我将迭代文本文件行,使用正则表达式分割行,搜索文件名 {$upc}.png 和将其重命名为 {$product_name}.png。
#!/bin/bash
while read -r line; do
if [[ $line =~ ([0-9]{12})(.*) ]]; then
upc="${BASH_REMATCH[1]}.png"
name="${BASH_REMATCH[2]}.png"
if [[ -f $upc ]]; then
if [[ ! -f $name ]]; then
cp "$upc" "$name"
else
echo "$name already exists"
fi
fi
fi
done < upcs.txt
答案3
一种方法如下。但请注意,这仅查看当前目录中的文件,并且不会递归到子目录中。
while IFS= read -r l <&3
do
barcode=${l%%[!0-9]*}
value=${l#"$barcode"}
[ -f "$barcode.png" ] && \
printf '%s.png ' "$barcode" "$value"
done 3< upcs.txt | xargs -rn 2 -t cp -pdf --