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

JS *_*wer 5 command-line bash files copy

我有大量文件夹,其中一个文件名为genome.txt我需要cp放入同一个文件夹中。我想弄清楚我该怎么做,所以这些文件的样子genome1.txtgenome2.txt等。我要寻找一个简单的解决这个。

Ser*_*nyy 4

Shell脚本及其使用

\n\n

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

\n\n
#!/bin/bash\nfind -name "genome.txt" -print0 | while IFS= read -r -d \'\' path\ndo\n    base=$(basename --suffix=".txt"  "$path")\n    new_path="${1%/}"/"$base"$counter".txt"\n    echo "$path" "$new_path"\n    counter=$(( $counter +1 ))\ndone\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n

例子:

\n\n
bash-4.3$ tree\n.\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 destination\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 dir1\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 genome.txt\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 dir2\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 genome.txt\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 dir3\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 genome.txt\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 move_enumerated.sh\n\n4 directories, 4 files\nbash-4.3$ ./move_enumerated.sh  ./destination\n./dir2/genome.txt ./destination/genome.txt\n./dir3/genome.txt ./destination/genome1.txt\n./dir1/genome.txt ./destination/genome2.txt\n
Run Code Online (Sandbox Code Playgroud)\n\n

改进脚本以提高灵活性

\n\n

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

\n\n
#!/bin/bash\nfind -name "genome.txt" -print0 | while IFS= read -r -d \'\' path\ndo\n    base=$(basename --suffix=".txt"  "$path")\n    new_path="${1%/}"/"$base"$counter".txt"\n    echo "$path" "$new_path"\n    counter=$(( $counter +1 ))\ndone\n
Run Code Online (Sandbox Code Playgroud)\n\n

测试运行:

\n\n
bash-4.3$ ./move_enumerated.sh "genome.txt"  "./testdir" "./testdir/destination"\n./testdir/dir2/genome.txt ./testdir/destination/genome.txt\n./testdir/dir3/genome.txt ./testdir/destination/genome1.txt\n./testdir/dir1/genome.txt ./testdir/destination/genome2.txt\n
Run Code Online (Sandbox Code Playgroud)\n\n

语法和操作理论

\n\n

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

\n\n

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

\n\n

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

\n\n

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

\n\n

有关更多信息,请阅读Shell 中的文件名和路径名:如何正确执行

\n