重命名文件名中包含多个变量的文件

Renaming files with multiple variables in the file names

我有多个这种格式的文件:this-is-text_r_123.txtthis-is-text.txt

我想做的(最好使用 for 循环)是将所有 this-is-text.txt 文件重命名为它们相应的 this-is-text_r_123.txt 匹配项,但有一个 i文件名中的 r。考虑到 this-is-text 是一个随机文本(一个文件与另一个文件不同),而上例中的 123 是 3 个数字的任意组合。所有文件都在一个目录中。

我尝试了 mvrename,但没有成功

我在这里搜索并查看了所有文件重命名问题,但 none 符合我的情况

解读 #1

如果您想将 *.txt 重命名为它们的 _r_<NUMBER>.txt 副本,并且您确定每个 .txt 文件只存在一个这样的文件,您可以使用以下方法:

for x in *.txt
do
    if [[ "$x" != *_r_* && "$x" != *_i_* ]]; then
        y="${x%.*}"
        echo "$x" "${y}_r_"*
    fi
done
  1. 我们遍历所有 *.txt 个文件。
    1. 我们检查它是否不是目标 _r_*.txt 也不是要重命名为 _i_*.txt 文件。
    2. 如果是,我们忽略它。如果不是,我们:
      1. Extract the base file name,没有扩展名,到 $y
      2. 输出源文件名和建议的目标文件名,依赖于* glob 星号运算符。如果匹配多个文件,它将打印所有文件。如果有none,则只打印源文件名。根据这些情况,您可以移动文件或保留文件。

要将变量 $z 中的 _r_ 替换为 _i_,您可能需要使用 z=${z/_r_/_i_}。这将在第 1.2.2 点中证明是有用的。

解读 #2

要移动每个 *.txt 文件并为其分配一个编号:

i=0
for x in *.txt
do
    let i+=1
    y="$(echo "$x"|sed 's/\(\.[a-z]*\)$/_r_'"$i"'/')"
    echo "$x" "$y"
done
  1. 首先我们声明变量i并将其设置为0。
  2. 然后我们遍历所有 *.txt 个文件。
    1. 然后我们使用let i+=1$i加1。
    2. 然后我们使用sed得到新的文件名,其中:
      1. 我们将文件扩展名 (.[a-z]*$) 替换 (s/A/B/) 为 _r_,
      2. 接着是 $i
      3. 后跟 s/// 运算符左侧的括号 \(\) 捕获的文件扩展名 (</code>)。</li> <li>我们用 <code>' 包装普通文本,用 " 包装变量。请注意表达式中的引号是如何更改两次的。
    3. 然后我们回显原始文件名和新文件名而不是移动,以便我们可以验证结果是否正确。

实际操作:

rr-@herp:~$ i=0; for x in *.txt; do let i+=1; y="$(echo "$x"|sed 's/\(\.[a-z]*\)$/_r_'"$i"'/')"; echo "$x" "$y"; done
mm todo.txt mm todo_r_1.txt
mm.txt mm_r_2.txt

注释

  1. 如果你需要验证第$i个文件是否已经存在,你可以使用if [ -f $target ].
  2. 您可以使用 find 来查找文件,但它更复杂,您应该在网上搜索如何使用 findfor 循环。

我将技术更改为 Python 以演示如何使用比 bash 更方便的语言来执行此操作:

#!/usr/bin/python3
import glob
import re

text_files = glob.glob('*.txt')

#divide the files into two groups: "normal" files without _r and "target" files with _r
normal_files = {}
target_files = {}
for path in text_files:
    #extract "key" (meaning part of file name without _r or _i)
    #as well as whether the file contains _r or _i, or not
    #using regular expressions:
    result = re.match('(?P<key>.*?)(?P<target>_[ri]_?\d*)?\..*$', path)
    if result:
        if result.group('target'):
            target_files[result.group('key')] = path
        else:
            normal_files[result.group('key')] = path

print(normal_files)
print(target_files)

#now figure out how to rename the files using the built dictionaries:
for key, path in normal_files.items():
    if key in target_files:
        target_path = target_files[key].replace('_r', '_i')
        print('Renaming %s to %s' % (path, target_path))

对于以下一组文件:

asd.txt
asd_r_1.txt
test test.txt
test test_r2.txt
another test_i_1.txt

此脚本将生成:

{'test test': 'test test.txt', 'asd': 'asd.txt'}
{'test test': 'test test_r2.txt', 'another test': 'another test_i_1.txt', 'asd': 'asd_r_1.txt'}
Renaming test test.txt to test test_i2.txt
Renaming asd.txt to asd_i_1.txt

你应该可以用这个移动文件。

如您所见,有效

如果您真的需要在bash中执行此操作,使用sedawk应该很容易移植。