我需要实现一个脚本(duplq.sh),它将使用命令行参数重命名当前目录中存在的所有文本文件。因此,如果执行了命令duplq.sh pic 0 3
,它将执行以下转换:
pic0.txt
必须重命名为pic3.txt
pic1.txt
至pic4.txt
pic2.txt
至pic5.txt
pic3.txt
至pic6.txt
等...
因此,第一个参数始终是文件的名称,第二个参数始终是正数。
我还需要确保在执行脚本时,第一次重命名(pic0.txt到pic3.txt),不会删除当前目录中的现有pic3.txt文件。
这是我到目前为止所做的事情:
#!/bin/bash
name="$1"
i="$2"
j="$3"
for file in $name*
do
echo $file
find /var/log -name 'name[$i]' | sed -e 's/$i/$j/g'
i=$(($i+1))
j=$(($j+1))
done
但是find命令似乎不起作用。你有其他解决方案吗?
答案 0 :(得分:1)
你试图解决的问题实际上有些棘手,我认为你并没有完全考虑过它。例如,duplq.sh pic 0 3
和duplq.sh pic 2 5
之间的区别是什么 - 它们看起来应该只添加3到数字,还是第二个跳过“pic0.txt”和“pic1.txt”?一个人对名为“pic”,“pic.txt”,“picture.txt”,“picture2.txt”,“pic2-2.txt”或“pic999.txt”的文件有什么影响。
到目前为止,您的脚本中还存在一些基本错误:
您应该(几乎)始终将变量引用放在double-qotes中,以避免意外的单词拆分和通配符扩展。因此,例如,使用echo "$file"
代替echo $file
。在for file in $name*
中,您应该在变量周围放置双引号,而不是*
,因为您希望将其视为通配符。因此,正确的版本是for file in "$name"*
不要将变量引用放在单引号中,它们不会在那里扩展。因此,在find
和sed
命令中,您没有传递变量的值,而是传递文字美元符号后跟字母。再次,使用双引号。此外,您在“名称”之前没有“$”,因此即使在双引号中也不会将其视为变量。
但是find
和sed
命令无论如何都不能做到你想要的。考虑find /var/log -name "name[1]"
- 查找名为“name1”的文件,而不是“name1”+某些扩展名。它查找当前目录和所有子目录,我很确定你不想要它。并且“1”("$i"
)可能不是当前文件名中的数字。假设存在名为“pic0.jpg”,“pic0.png”和“pic0.txt”的文件 - 在第一次迭代中,循环可能会发现所有三个都具有类似“pic0 *”的模式,然后在第二个和第三次迭代试图找到“pic1 *”和“pic2 *,它们不存在。另一方面,假设有名为”pic0.txt“,”pic5.txt“和”pic8.txt“的文件 - 再次,它可能会寻找“pic0 *”(ok),然后是“pic1 *”(未找到),然后是“pic2 *”(同上)。
此外,如果你得到多位数字,“name [10]”模式将匹配“file0”和“file1”,但不匹配“file10”。我不知道为什么你在那里添加括号,但他们没有做你想做的任何事情。
您已经在$file
变量中一次列出了一个文件,再次使用不同的标准进行搜索只会增加混淆。
此外,在脚本中没有任何一点你实际上重命名任何东西。 find | sed
行将(如果有效)打印文件的新名称,但实际上不会重命名。
顺便说一句,当你使用mv
命令时,使用mv -n
或mv -i
来保护它免于在发生名称冲突时无声地和不可挽回地覆盖文件。
为了防止在递增文件编号时进行覆盖,您需要以反向数字顺序重命名(即在重命名“pic0”之前将“pic3.txt”重命名为“pic6.txt”。 txt“to”pic3.txt“)。这特别棘手,因为如果你只是按反向字母顺序排序文件名,你将在“pic10.txt”之前得到“pic7.txt”。但是,如果不首先删除“pic”和“.txt”部分,则无法进行数字排序。
IMO这实际上是要解决的最棘手问题,以使此脚本正常工作。将最大索引号指定为参数之一可能是最简单的,并让它从那里开始并倒计时到0(循环遍历数字而不是文件),然后为每个数字迭代匹配的文件(例如“pic0.jpg”,“pic0.png”和“pic0.txt”)。
答案 1 :(得分:0)
所以我假设0 3只是对旧数字和新数字之差的测量,相当于1 4或100 103.
要避免覆盖现有文件,请创建一个新的临时目录,将所有受影响的文件移动到那里,然后将所有文件移回最后。
#/bin/bash
#
# duplq.sh pic 0 3
base="$1"
delta=$(( $3 - $2 ))
# echo delta $delta
target=$(mktemp -d)
echo $target
# /tmp/tmp.7uXD2GzqAb
add () {
f="$1"
b="$2"
d=$3
num=${f#./${b}}
# echo -e "file: $f \tnum: $num \tnum + d: $((num + d))" ;
echo -e "$((num + d))" ;
}
for f in $(find -maxdepth 1 -type f -regex ".*/${base}[0-9]+")
do
newnum=$(add "$f" "${base}" $delta)
echo mv "$f" "$target/${base}$newnum"
done
# exit
echo mv $target/${base}* .
首先,我尝试使用bash语法来检查是否删除前缀(pic)只会导致数字剩余。我也没有使用扩展名.txt - 这是留给读者的练习。从问题不清楚 - 它从未被明确告知,所有文件共享相同的扩展名,但示例中的所有文件都有。
使用-regex"。* / $ {base} [0-9] +")在find中,值保证只是数字。
num=${f#./${b}}
从文件f中删除基数(" pic")。 Delta d被添加。
我没有真正感动,而是回应了mv-command。
@TODO:实施文件扩展名保护。
另外还有两个陷阱:如果你有3个文件pic0,pic00和pic000,它们都会被重命名为pic3。并且pic08将被切割为pic,08 08将被尝试以八进制数字(或09或012129等)读取并导致错误。
解决此问题的一种方法是,将提取的数字(001或018)添加到" 1",然后添加3,并删除前导1:
001 1001 1004 004
018 1018 1021 021
但这个聪明的解决方案会带来新的问题:
999 1999 2002 002?
因此领先的1必须被削减,领先的2必须减少1.但是现在,如果delta更大,那么让我们说300:
018 1018 1318 318
918 1918 2218 1218
嗯 - 这似乎有效。