如何在bash中将文件名一部分的数字存储为变量

如何在bash中将文件名一部分的数字存储为变量

我试图将文件名一部分的数字存储为变量,以便我可以通过循环一次更改和重命名一堆文件。文件名是trimmed-barcode*.1.fastq.gz,其中*是一个可变的两位或三位数字,我想将其保存为num。这将允许我将 $num 乘以我之前定义的 $number 变量,并用相乘的数字重命名每个文件(但现在我只是用 echo 测试它)。如何存储文件名中的两位或三位数?

for infile in trimmed-barcode*.1.fastq.gz
  do num= #how do I get this number
  num2=$(($num * $number))
  echo "trimmed-barcode${num2}.1.fastq.gz"
  done

答案1

如果您使用bash脚本,您可以从字符串中提取两个数字。例如

var="abcdefg"
echo "${var:3:2}"    # Outputs "de"

有了这个,我们就可以像这样调整你的脚本

#!/bin/bash
for infile in trimmed-barcode??.1.fastq.gz
do
    num="${infile:15:2}"    # Two characters starting at position 15
    result=$(( ${num#0} * number ))
    echo "trimmed-barcode$result.1.fastq.gz"
done

在相乘时$num$number我们必须从值中去除任何前导零,这样bash就不会尝试将其视为八进制。就是这样${num#0}


您已将问题修改为询问两个或三个数字。这显着改变了实现。

  1. 您可以重复循环,但这次匹配三个数字:

    for infile in trimmed-barcode??.1.fastq.gz
    do
        # Code as above for two digit extracts
    done
    
    for infile in trimmed-barcode???.1.fastq.gz
    do
        # Modify code as above to process three digit values
    done
    
  2. 您可以更改代码以删除不变的部分,假设剩下的内容一定是感兴趣的值:

    for infile in trimmed-barcode*.1.fastq.gz
    do
        num=${infile#trimmed-barcode}    # Strip leading text
        num=${num%.1.fastq.gz}           # Strip trailing text
        result=$(( ${num#0} * number ))
        echo "trimmed-barcode$result.1.fastq.gz"
    done
    

答案2

for file in trimmed-barcode*.1.fastq.gz; do
    x=${file#trimmed-barcode}
    num=${x%.1.fastq.gz}
    echo "$file: $num"
done

或者在 Bash 中,您可以使用正则表达式匹配来选择文件名的所需部分:

for file in trimmed-barcode??.1.fastq.gz; do
    [[ $file =~ trimmed-barcode(.*)\.1\.fastq\.gz ]]
    num=${BASH_REMATCH[1]};
    echo "$file: $num"
done

或者,如果您想修剪它,只需选择第一个点之前的两个字符[[ $file =~ (..)\. ]]

答案3

要将文件名中的两位数字存储为循环中的变量,可以在 bash 中使用文件名扩展和字符串操作。这是一个例子:

for infile in trimmed-barcode*.1.fastq.gz
do
  num="${infile:14:2}"
  num2=$((num * number))
  echo "trimmed-barcode${num2}.1.fastq.gz"
done

在此代码中,我们使用 ${infile:14:2} 字符串扩展从文件名中提取从索引 14 开始的两位数。然后将该数字 (num) 乘以 $number 变量并将结果存储在编号2。最后,我们用修改后的数字回显生成的文件名。

请记住根据文件名中数字的实际位置调整索引(在本例中为 14)。

答案4

以下使用 perlrename实用程序:

注意:perlrename也称为file-renameperl-rename、 或prename,具体取决于您的发行版。不要将其与具有完全不同且不兼容的功能和命令行选项的rename实用程序混淆。 util-linuxPerl 重命名允许您使用任意复杂的 Perl 代码来重命名文件,但最常用于对文件名执行简单的类似 sed 的 s/search/replace/ 操作。

首先创建一些文件名进行测试:

for i in 11 234 56 789 ; do touch "trimmed-barcode$i.1.fastq.gz" ; done

然后重命名它们:

export number=2
rename -n 's/^(trimmed-barcode)(\d{2,3})(\.1\.fastq\.gz)$/$1 . $2 * $ENV{number} . $3/e' trimmed*

示例输出:

rename(trimmed-barcode11.1.fastq.gz, trimmed-barcode22.1.fastq.gz)
rename(trimmed-barcode234.1.fastq.gz, trimmed-barcode468.1.fastq.gz)
rename(trimmed-barcode56.1.fastq.gz, trimmed-barcode112.1.fastq.gz)
rename(trimmed-barcode789.1.fastq.gz, trimmed-barcode1578.1.fastq.gz)

-n选项使其成为一次试运行,因此它仅显示它的内容做。要实际重命名文件,请删除-n或将其替换-v为详细输出。

$number变量必须导出到环境中,以便rename脚本可以通过哈希访问它%ENV。或者,您可以在同一命令行上分配变量(例如number=2 rename -n '...' trimmed*(具有为该命令临时导出变量的效果)或将其硬编码到脚本中。

要使其适用于 之前的任意数量的数字(即一位或多位),.1.fastq.gz请将 更改\d{2,3}\d+

要使其适用于数字之前的任何文件名前缀(不仅仅是“修剪条形码”)以及第一个之后的任何扩展名.,请将其更改为:

rename -n 's/(.*?)(\d{2,3})(\..*)/$1 . $2 * $ENV{number} . $3/e' trimmed*

该脚本利用 Perl 的功能,使用/e正则表达式修饰符在替换运算符的右侧(替换)部分执行 Perl 代码s///。在本例中,.是 perl 的字符串连接运算符,因此代码将第一个捕获组 ( $1) 与第二个捕获组 ( $2) 乘以$number环境变量以及第三个捕获组 ( $3) 连接起来。

顺便说一句,perlrename不会覆盖现有文件,除非您使用-f/--force选项强制它。

与替换运算符左侧(搜索)部分的正则表达式不匹配的文件名将不会以任何方式重命名或修改。

相关内容