一行代码更改文件名的开头和结尾

One-liner to change start and end of the filename

我需要将目录中具有前缀的所有文件重命名为具有特殊后缀的相应名称。

例如,假设我有一堆文件,名称如下:

first_0001.txt
second_0001.txt
first_0002.txt
second_0002.txt
...

我需要做的是重命名它们,使它们对应的名称为:

0001_1.txt
0001_2.txt
0002_1.txt
0002_2.txt
...

我试过

for file in `ls`; do
    mv $file ${file/first*/*_1.txt}
done

但这只是将所有文件重命名为具有相同的名称,这是不需要的。所以变化的格局是:

  1. 如果文件名以“first_”开头,则应删除此部分,并在文件扩展名前添加后缀“_1”。例如first_0001.txt应该改为0001_1.txt
  2. 同理,如果文件名以“second_”开头,则应删除这部分,并在文件扩展名前添加后缀“_2”。 例如second_0001.txt应该改为0001_2.txt

不是单行,但如果您的 bash 版本支持 BASH_REMATCH

#!/usr/bin/env bash

for file in *.txt; do
  [[ $file =~ ^(first|second)_(000[12])(\.txt)$ ]] &&
  if [[ "${BASH_REMATCH[1]}" == first ]]; then
    echo mv -v "$file" "${BASH_REMATCH[2]}_1${BASH_REMATCH[3]}"
  elif [[ "${BASH_REMATCH[1]}" == second ]]; then
    echo mv -v "$file" "${BASH_REMATCH[2]}_2${BASH_REMATCH[3]}"
  fi
done

如果您对输出满意,请删除 echo

如果您有基于 Perl 的 rename 程序(有时称为 prename),那么您可以使用它来进行这两个映射。这些示例显示了前缀和后缀之间的数字字符串——可以轻松修改正则表达式以处理更通用的名称。

rename 's/first_(\d)+\.txt/_1.txt/' first_*.txt
rename 's/second_(\d+)\.txt/_2.txt/' second_*.txt

但是,这不是一个命令。显然,您可以在它们之间放置一个分号,并将它们放在同一行;我不知道这是否重要。将它们结合起来充其量是棘手的——在我看来不值得付出努力。

我对单线过敏,所以我会这样做:

#!/bin/sh -
for pathname in ./*.*; do
  filename=${pathname##*/}
  case $filename in
  'first_'*  ) postfix=_1 ;;
  'second_'* ) postfix=_2 ;;
  # ...
  *          ) continue ;;
  esac
  path=${pathname%/*}
  newname=${filename#*_}  # temporary
  newname=${newname%.*}
  extension=${pathname##*.}
  # remove `echo' if it looks good
  echo mv -- "$pathname" \
    "$path/$newname$postfix.$extension"
done

我会做以下事情:

for f in first_*; do g=${f#*_}; mv $f ${g%.*}_1.txt; done
for f in second_*; do g=${f#*_}; mv $f ${g%.*}_2.txt; done

但是如果你真的想要一个疯狂的oneliner,你可以这样做:

for pair in first,1 second,2 ; do postfix=_${pair#*,}.txt; for file in ${pair%,*}_*.txt; do rightpart=${file#*_}; echo $file ${rightpart%.*}$postfix; done; done

扩展 ,如果您的 rename 有 -E 选项:

rename -n -E 'my %map = (first => 1, second => 2)' \
          -e 's/(\D+)_(\d+)(\..*)/_$map{}/' {first,second}*