mv:如果目标存在,则在文件名中添加数字

mv:如果目标存在,则在文件名中添加数字

我正在将文件移动到不同的文件夹,并且如果已存在同名文件(旧文件应保持不变),则希望向新移动的文件添加某种索引。例如,如果file.pdf存在,我更喜欢类似file1.pdffile_1.pdf的下一个同名文件。

这里我找到了相反想法的变体 - 但我不想进行“备份”。

是否mv有一些针对该场景的开箱即用参数?我使用 Ubuntu Linux。

答案1

正如您链接的问题的答案已经指出的那样,mv可以为文件添加后缀,否则这些文件会被您移动的文件覆盖,并使用数字为它们提供唯一的文件名:

mv --backup=t <source_file> <dest_file>

该命令的工作原理是将下一个未使用的数字后缀附加到目标目录中第一个文件中。您正在移动的文件将保留其原始名称。

但是,这会附加诸如 之类的后缀.~1~,这似乎不是您想要的:

$ ls
file.pdf
file.pdf.~1~
file.pdf.~2~

您可以在第二步中重命名这些文件,以file_1.pdf代替的格式获取名称file.pdf.~1~,例如:

rename 's/((?:\..+)?)\.~(\d+)~$/_$2$1/' *.~*~

这将获取所有以不需要的备份后缀结尾的文件(通过与 shell glob 匹配*.~*~),并让该rename工具尝试匹配((?:\..+)?)\.~(\d+)~$文件名上的正则表达式。如果匹配,它将捕获类似后缀的索引.~1~作为第二组 ( $2),并且可选地,如果文件名在该后缀之前有扩展名,例如.pdf,则将由第一组 ( $1) 捕获。然后,它将完整匹配的文件名部分替换为_$2$1,并插入捕获的值而不是占位符。

基本上它会将eg重命名file.pdf.~1~file_1.pdfsomething.~42~to something_42,但它无法检测文件是否有多个扩展名,因此egarchive.tar.gz.~5~会变成archive.tar_5.gz

答案2

我遇到的问题是 BASH 脚本在操作期间遇到/覆盖同名文件mv

解决mv --backup=t <src> <dest>方案在这里,以及https://serverfault.com/questions/267255/mv-rename-if-exists效果很好。不过我也想保留文件扩展名。

这是一个解决方案。

[victoria@victoria out]$ ls -l

total 20
-rw-r--r-- 1 victoria victoria 6 May 23 18:13 apple1.txt
-rw-r--r-- 1 victoria victoria 6 May 23 18:13 apple2.txt
-rw-r--r-- 1 victoria victoria 6 May 23 18:13 apple3.txt
-rw-r--r-- 1 victoria victoria 6 May 23 18:13 apple4.txt
-rw-r--r-- 1 victoria victoria 6 May 23 18:13 apple5.txt

[victoria@victoria out]$ for f in *; do mv -f --backup=t "$f" banana.txt; done

[victoria@victoria out]$ ls -l
total 20
-rw-r--r-- 1 victoria victoria 6 May 23 18:13 banana.txt
-rw-r--r-- 1 victoria victoria 6 May 23 18:13 banana.txt.~1~
-rw-r--r-- 1 victoria victoria 6 May 23 18:13 banana.txt.~2~
-rw-r--r-- 1 victoria victoria 6 May 23 18:13 banana.txt.~3~
-rw-r--r-- 1 victoria victoria 6 May 23 18:13 banana.txt.~4~

[victoria@victoria out]$ for f in *; do mv 2>/dev/null -v "$f" "`echo $f | sed -r 's/(.*)\.(.*)\.~([0-9]{1,})~$/\1_\3.\2/'`"; done

renamed 'banana.txt.~1~' -> 'banana_1.txt'
renamed 'banana.txt.~2~' -> 'banana_2.txt'
renamed 'banana.txt.~3~' -> 'banana_3.txt'
renamed 'banana.txt.~4~' -> 'banana_4.txt'

[victoria@victoria out]$ ls -l

total 20
-rw-r--r-- 1 victoria victoria 6 May 23 18:13 banana_1.txt
-rw-r--r-- 1 victoria victoria 6 May 23 18:13 banana_2.txt
-rw-r--r-- 1 victoria victoria 6 May 23 18:13 banana_3.txt
-rw-r--r-- 1 victoria victoria 6 May 23 18:13 banana_4.txt
-rw-r--r-- 1 victoria victoria 6 May 23 18:13 banana.txt

[victoria@victoria out]$ 

解释:

  • 使用sed正则表达式命令我捕获源文件名的三个部分,

/(.*)\.(.*)\.~([0-9]{1,})~$/

即,在序列匹配中:

  • 一切:(.*) # captured as group \1
  • 时期\.
  • 一切:(.*) # captured as group \2
  • 时期\.
  • 波形符:~
  • 任意数量的数字:([0-9]{1,}) # captured as group \3
  • 第二个波形符和行尾:~$

并重新排列它们:

/\1_\3.\2/ # 注意句点的位置,无需在此处转义`

请注意在-quoted命令`的开头/结尾处使用反引号。"echo

2>/dev/null忽略任何虚假警告(如果发生)。

-v如果您不希望命令输出详细信息,请忽略该标志mv


也可以看看:

答案3

好吧,不要以我不差的 bash 技能来评判我,但这个解决方案对我有用。 (我很感激字节指挥官解决方案但这是由于它的限制而不是我想要的)

所以这是我的小脚本来完成这项工作......

  • $2是路径
  • $3文件名
  • $punktpdf只是“.pdf”

所以这是我的小脚本......

if [ -s $2$3$punktpdf ]; then
    for i in `seq 1 100000`;
        do
            if [ ! -s $2$3$i$punktpdf ]; then
                if mv scan.pdf $2$3$i$punktpdf; then                        
                    echo $3$i$punktpdf
                    exit 0
                    break
               else                        
                    echo 1
                    break
               fi
           fi
        done
    else
        #Regular mv
    fi

答案4

我创建了move命令。 move如果文件存在则命令添加索引。

npm i -g @gauravnumber/move

例子

文件夹结构

.
├── 1.txt
├── 2.txt
├── 3.txt
├── 4.txt
├── 5.txt
└── 6.txt

输入以下命令。

move 1.txt 2.txt

2.txt文件已存在。move命令在文件上附加索引。运行以上命令后。文件夹结构如下所示。

.
├── 2_1.txt
├── 2.txt
├── 3.txt
├── 4.txt
├── 5.txt
└── 6.txt

move命令还支持多个文件。

move *.jpg dirname
move *.png *.jpg dirname
move dirname1 dirname2
move dirname1/* dirname2

这是链接到回购协议

相关内容