使用命令行参数Bash更改文件的名称

时间:2018-04-22 19:10:32

标签: linux bash shell command-line-arguments file-rename

我需要实现一个脚本(duplq.sh),它将使用命令行参数重命名当前目录中存在的所有文本文件。因此,如果执行了命令duplq.sh pic 0 3,它将执行以下转换:

pic0.txt必须重命名为pic3.txt

pic1.txtpic4.txt

pic2.txtpic5.txt

pic3.txtpic6.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命令似乎不起作用。你有其他解决方案吗?

2 个答案:

答案 0 :(得分:1)

你试图解决的问题实际上有些棘手,我认为你并没有完全考虑过它。例如,duplq.sh pic 0 3duplq.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"*

  • 不要将变量引用放在单引号中,它们不会在那里扩展。因此,在findsed命令中,您没有传递变量的值,而是传递文字美元符号后跟字母。再次,使用双引号。此外,您在“名称”之前没有“$”,因此即使在双引号中也不会将其视为变量。

  • 但是findsed命令无论如何都不能做到你想要的。考虑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 -nmv -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 

嗯 - 这似乎有效。