【问题标题】:Renaming files with multiple variables in the file names重命名文件名中包含多个变量的文件
【发布时间】:2015-09-05 08:17:27
【问题描述】:

我有多个采用这种格式的文件: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,但没有成功

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

【问题讨论】:

  • from & to 文件名在哪里定义?
  • 从:this-is-text.txt 到 this-is-text_i_123.txt,每个文件的“this is text”和“123”都不同。并且“this_is_text”必须匹配 this-is-text_r_123.txt 中的“this-is-text”

标签: bash for-loop rename mv


【解决方案1】:

解释#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 星号运算符。如果匹配多个文件,它将打印所有文件。如果没有,它将只打印源文件名。根据这些情况,您可以移动文件或保留它。

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

在行动中看到它:

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

注意事项

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

【讨论】:

  • 感谢您的回答,但它对我不起作用。我将提供一个示例:我有 abc.txt 和 abc_r25.txt,我想将 abc.txt 重命名为 abc_i25.txt。每个文件的“abc”和“25”都不同。
  • @nytrook 查看我刚刚添加的解释 #1。
  • 一句忠告,请确保引用所有变量(不仅仅是您认为重要的变量) - 您可能认为 echo $x $y 很好,但如果文件名包含一个全局字符。
  • @TomFenech 你是对的;幸运的是我还没有偶然发现这样的文件。
  • 就像一个魅力。惊人的解释。我学到了很多东西。非常感谢。
【解决方案2】:

我将技术更改为 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 进行移植应该很容易。

【讨论】:

  • 好吧,是的,我真的很想看看这个的 bash 版本。非常感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-11-20
  • 1970-01-01
  • 1970-01-01
  • 2014-03-05
  • 1970-01-01
  • 2013-10-30
  • 1970-01-01
相关资源
最近更新 更多