【问题标题】:Renaming multiple files with multiple field separator in awk在awk中使用多个字段分隔符重命名多个文件
【发布时间】:2021-12-18 21:27:31
【问题描述】:

我需要同样将以下文件从 PFSI4C.CSC.CCC.FSIContractData20211008.zip 重命名为 TFSI4C.CSC.CCC .FSIContractData20211104.zip.

每个文件的名称都应以“T”开头并以当前系统日期 + .zip 结尾

我正在尝试循环文件,它看起来像这样:

for FILENAME in PFSI4C.CSC.CCC.FSIContractData20211008; do
    NEW_FILENAME_HEADER=`echo $FILENAME | awk -F "." '{ print $1"."$2"."$3 }'` # which would takes PFSI4C.CSC.CCC.
    NEW_FILENAME_SUFFIX=`echo $FILENAME | awk -F "[.|Data20]" '{ print "."$4 }'` # this part where I can't figure out to take only "FSIContract"
    NEW_FILENAME="${NEW_FILENAME_HEADER}.""${NEW_FILENAME_SUFFIX}""Data20""${DATE}".zip" # which should make "TFSI4C.CSC.CCC.FSIContractData20211104.zip."
    mv $FILENAME $NEW_FILENAME
  done
  

FYI $DATE 在我们的脚本中定义如下:DATE='date +'%y%m%d' 例如 211104

提前致谢!

【问题讨论】:

标签: command-line rename


【解决方案1】:

使用 Perl 的 rename 命令,您可以尝试以下代码。我在这里使用-n 选项在 DRY RUN 模式下对其进行测试,它只会打印文件名从哪个文件名(当前)到哪个文件名(必填)将被更改;一旦您对显示的输出感到满意,请删除代码中的-nDATE 变量 (DATE='20211104') 也是一个 shell 变量,其中包含需要在新文件名中的日期值。

rename -n 's:^.(.*)\d{8}(\.zip)$:T$1$2:; s:\.zip$:'"$DATE"'.zip:' *.zip

输出如下:

rename(PFSI4C.CSC.CCC.FSIContractData20211008.zip, TFSI4C.CSC.CCC.FSIContractData20211104.zip)

rename代码解释:

  • -n:在 DRY RUN 模式下运行 rename 命令。
  • s:^.(.*)\d{8}(\.zip)$:T$1$2:;:在rename 代码中运行第一组替换。在它创建 2 个捕获组的地方,第一个捕获组包含从第二个字符开始到 8 位数字之前的所有内容,并且第二个捕获组在文件名末尾包含 .zip。同时根据要求将其替换为T1$2
  • s:\.zip$:'"$DATE"'.zip::在rename 代码中运行第二组替换。其中.zip$ 带有shell 变量DATE 以及根据要求的.zip。

【讨论】:

    【解决方案2】:

    首先,您应该使用date +%Y%m%d(4 位数年份)而不是date +%y%m%d(2 位数年份)来获取当前日期。以下假设您这样做。如果不是选项,请将 20 添加到 $DATE

    如果你的文件名看起来像你展示的例子,bash 替换就可以做到。首先计算长度,提取日期前倒数第二个字符,添加T,添加$DATE.zip

    len="${#FILENAME}"
    NEW_FILENAME="T${FILENAME:1:$((len-13))}$DATE.zip"
    

    但您也可以使用sed,它提供了更多的灵活性。例如,它可以处理可变位数的结束日期:

    NEW_FILENAME=$(echo "$FILENAME" | sed 's/.\(.*[^0-9]\)\?[0-9]*\.zip/T\1'"$DATE"'.zip/')
    

    或者,使用 bash(此处为字符串)和 GNU sed 或其他支持 -E 选项(用于扩展正则表达式)的 sed 更优雅一点:

    NEW_FILENAME=$(sed -E 's/.(.*[^0-9])?[0-9]*\.zip/T\1'"$DATE"'.zip/' <<< "$FILENAME")
    

    【讨论】:

    • 不幸的是,这部分 (FSIContract) 对于所有文件都不相同。它像“FSICustomerContact”、“FSILocation”等变化。
    • 这没关系。我展示的命令是删除第一个和最后 12 个字符。他们不在乎中间是什么。试一试。
    • 当然你的只适用于 PFSI4C.CSC.CCC.FSIContractData20211008.zip 而不是 PFSI4C.CSC.CCC.FSICustomerContact20211008.zip, PFSI4C.CSC.CCC.FSILocation20211008.zip
    • 好的,我再试一次
    • 我不确定我理解为什么你认为它不起作用,但我用你的另外两个例子进行了测试,它就像一个魅力。第一个版本(bash 参数替换)仅在名称以 8 个字符的日期结尾且后跟 .zip 扩展名时才有效。其他两个 sed 可以容忍任意位数的日期。
    【解决方案3】:

    假设:

    • 将第一个字符(OP 示例中的P)替换为T
    • 将最后 10 个字符 (YYMMDD.zip) 替换为 $DATE.zip(OP 已定义 $DATE
    • 所有文件都包含20YYMMDD,因此我们无需担心名称中包含19YYMMDD21YYMMDD 等字符串

    使用parameter substitutions 的一个想法(这也消除了执行各种echoawksed 命令的子进程调用的开销):

    DATE='211104'
    FILENAME='PFSI4C.CSC.CCC.FSIContractData20211008.zip'
    
    NEWFILENAME="T${FILENAME/?}"                           # prepend "T"; "/?" => remove first character
    NEWFILENAME="${NEWFILENAME/??????.zip}${DATE}.zip"     # remove string "??????.zip"; append "${DATE}.zip"
    
    echo mv "${FILENAME}" "${NEWFILENAME}"
    

    这会生成:

    mv PFSI4C.CSC.CCC.FSIContractData20211008.zip TFSI4C.CSC.CCC.FSIContractData20211104.zip
    

    一旦 OP 对代码的准确性感到满意,就可以删除 echo 以启用 mv 命令的执行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-07-24
      • 2013-03-17
      • 1970-01-01
      • 2014-10-14
      • 1970-01-01
      • 2012-08-25
      • 1970-01-01
      相关资源
      最近更新 更多