在Unix中通过插入-和_字符重命名多个日期时间文件

nfg76nw0  于 2022-11-04  发布在  Unix
关注(0)|答案(2)|浏览(208)

我想重命名目录中的许多文件,以便根据特定约定可以识别它们:

SURFACE_OBS:2019062200
SURFACE_OBS:2019062206
SURFACE_OBS:2019062212
SURFACE_OBS:2019062218
SURFACE_OBS:2019062300

等等。
如何在UNIX中将它们重命名为以下名称?

SURFACE_OBS:2019-06-22_00
SURFACE_OBS:2019-06-22_06
SURFACE_OBS:2019-06-22_12
SURFACE_OBS:2019-06-22_18
SURFACE_OBS:2019-06-23_00
mbskvtky

mbskvtky1#

一个使用mv和参数扩展的bash shell循环可以做到这一点:

for file in *:[[:digit:]][[:digit:]][[:digit:]][[:digit:]][[:digit:]][[:digit:]][[:digit:]][[:digit:]][[:digit:]][[:digit:]]
do
  prefix=${file%:*}
  suffix=${file#*:}
  mv -- "${file}" "${prefix}:${suffix:0:4}-${suffix:4:2}-${suffix:6:2}_${suffix:8:2}"
done

此循环将选取与模式匹配的每个文件:

  • *--任何内容
  • :--冒号
  • [[:digit:]][[:digit:]][[:digit:]][[:digit:]][[:digit:]][[:digit:]][[:digit:]][[:digit:]][[:digit:]][[:digit:]]-- 10位数字

...然后通过在所需位置插入短划线和下划线对其进行重命名。
我仔细地选择了循环的通配符,这样它就可以匹配“输入”文件,而不是重命名的文件。如果实际的文件名有边缘情况,导致通配符失败(并因此再次重命名文件),请根据需要调整模式。

ss2ws0br

ss2ws0br2#


# !/bin/bash

strindex() { 
  # get position of character in string
  x="${1%%"$2"*}"
  [[ "$x" = "$1" ]] && echo -1 || echo "${#x}"
}

get_new_filename() {
  # change filenames like:  SURFACE_OBS:2019062218
  # into filenames like:    SURFACE_OBS:2019-06-22_18

  src_str="${1}"

  # add last underscore 2 characters from end of string
  final_underscore_pos=${#src_str}-2
  src_str="${src_str:0:final_underscore_pos}_${src_str:final_underscore_pos}"

  # get position of colon in string
  colon_pos=$(strindex "${src_str}" ":")

  # get dash locations relative to colon position
  y_dash_pos=${colon_pos}+5
  m_dash_pos=${colon_pos}+8

  # now add dashes in date
  src_str="${src_str:0:y_dash_pos}-${src_str:y_dash_pos}"
  src_str="${src_str:0:m_dash_pos}-${src_str:m_dash_pos}"
  echo "${src_str}"
}

# accept path as argument or default to /tmp/baz/data

target_dir="${1:-/tmp/baz/data}"

while read -r line ; do
  # since file renaming depends on position of colon extract 
  # base filename without path in case path has colons 
  base_dir=${line%/*}
  filename_to_change=$(basename "${line}")
  echo "mv ${line} ${base_dir}/$(get_new_filename "${filename_to_change}")"

  # find cmd attempts to exclude files that have already been renamed 
done < <(find "${target_dir}" -name 'SURFACE*' -a ! -name '*_[0-9]\{2\}$')

相关问题