将同名文件复制到同一目录中

将同名文件复制到同一目录中

我有大量文件夹,每个文件夹都包含一个文件名genome.txt,我需要将它们cp放在同一个文件夹中。我正在尝试弄清楚如何做到这一点,以便文件看起来像genome1.txtgenome2.txt等等。我正在寻找一个简单的解决方案。

答案1

Shell脚本及其使用

这可以通过一个利用find ...|while read var ; do ... done结构(在处理文件名时非常常见)的简单 shell 脚本来完成。下面的 bash 脚本对当前(最顶层)目录进行操作,并接受单个参数作为目标。

#!/bin/bash
find -name "genome.txt" -print0 | while IFS= read -r -d '' path
do
    base=$(basename --suffix=".txt"  "$path")
    new_path="${1%/}"/"$base"$counter".txt"
    echo "$path" "$new_path"
    counter=$(( $counter +1 ))
done

>>>注意<<<:脚本echo仅用于测试目的。当您对结果路径满意时,将其替换echomv移动所有文件名或cp复制所有文件名。

例子:

bash-4.3$ tree
.
├── destination
├── dir1
│   └── genome.txt
├── dir2
│   └── genome.txt
├── dir3
│   └── genome.txt
└── move_enumerated.sh

4 directories, 4 files
bash-4.3$ ./move_enumerated.sh  ./destination
./dir2/genome.txt ./destination/genome.txt
./dir3/genome.txt ./destination/genome1.txt
./dir1/genome.txt ./destination/genome2.txt

改进脚本以获得更大的灵活性

该脚本可以进一步改进,使其更加通用,用户可以将文件名、要遍历的顶级目录和目标全部指定为命令行参数:

#!/bin/bash
find "$2"  -name "$1" -print0 | while IFS= read -r -d '' path
do
    base=$(basename --suffix=".txt"  "$path")
    new_path="${3%/}"/"$base"$counter".txt"
    echo "$path" "$new_path"
    counter=$(( $counter +1 ))
done

测试运行:

bash-4.3$ ./move_enumerated.sh "genome.txt"  "./testdir" "./testdir/destination"
./testdir/dir2/genome.txt ./testdir/destination/genome.txt
./testdir/dir3/genome.txt ./testdir/destination/genome1.txt
./testdir/dir1/genome.txt ./testdir/destination/genome2.txt

语法和操作理论

总体而言,脚本利用了command | while read variable ; do ... done结构。这是一种非常常见的方法,它经常用于避免处理ls可能破坏脚本的复杂文件名。

在管道的左侧,我们有find命令,它将目录作为参数(如果没有给出,findLinux 中使用的 GNU 会假定为.- 当前工作目录)。其他选项包括-name我们正在搜索的特定文件名,以及-print0用于以不可打印\0字符分隔的方式输出结果的选项。它经常用于避免在换行符或其他字符上进行拆分,因为这些字符可能会出现在文件名本身中,从而破坏脚本。

在管道的右侧,我们有while IFS= read -r -d '' ; do . . . done结构。内置 shell 的while循环read经常用于实际stdin输入,在本例中来自管道。IFS= -r-d ''是必要的,以确保我们安全地接收文件名,并识别每个项目都以 分隔\0

脚本的其余部分相当简单。我们使用basename命令提取文件的基本名称。由于在这种情况下,我们专门处理已知扩展名并希望文件名中有一个点,因此我们可以使用--suffix=".txt"去掉该部分,留下genome部分。然后,我们通过连接目标、基本名称和计数器变量来构建文件的新路径。请注意,"${3%/}" 在改进的脚本中,我们使用参数扩展和参数(目标文件夹)。这样做是为了确保无论用户是否/在命令行(./destination./destination/)中添加字符,我们都只提取裸目录名,并通过不同的方式将其/与基本名称连接起来。还要注意,counter变量最初没有设置,所以我们收到的第一个文件名将是纯文本。genome.txt之后,计数器变量将递增并因此被创建,并将在我们处理其他文件名时显示出来。

欲了解更多信息,请阅读Shell 中的文件名和路径名:如何正确使用

相关内容