Bash: 如何将多个同名文件复制到多个文件夹

Bash: how to copy multiple files with same name to multiple folders

我正在 Linux 机器上工作。 我有很多同名文件,目录结构如下:

P45_input_foo/result.dat
P45_input_bar/result.dat
P45_input_tar/result.dat
P45_input_cool/result.dat ...

很难一一复制。我想将它们复制到另一个名为 data 的文件夹中,文件夹名称和文件名相似:

/data/foo/result.dat
/data/bar/result.dat
/data/tar/result.dat
/data/cool/result.dat ...

我应该怎么做而不是一张一张地复制它们?

您需要提取“_”后的第三项:

P45_input_foo --> foo

创建目录(如果需要)并将文件复制到其中。像这样的东西(未经测试,可能需要编辑):

 STARTING_DIR="/"
cd "$STARTING_DIR"
VAR=$(ls -1)
while read DIR; do
  TARGET_DIR=$(echo "$DIR" | cut -d'_' -f3)
  NEW_DIR="/data/$DIR"
  if [ ! -d "$NEW_DIR" ]; then
    mkdir "$NEW_DIR"
  fi
  cp "$DIR/result.dat" "$NEW_DIR/result.dat"
  if [ $? -ne 0 ];
    echo "ERROR: encountered an error while copying"
  fi
done <<<"$VAR"

说明:假设您提到的所有路径都在根 / 下(如果没有相应地更改 STARTING_PATH)。使用 ls 可以获得目录列表,将输出存储在 VAR 中。将 VAR 的内容传递给 while 循环。

在 bash 中使用 for 循环 :

# we list every files following the pattern : ./<somedirname>/<any file>
# if you want to specify a format for the folders, you could change it here
# i.e. for your case you could write 'for f in P45*/*' to only match folders starting by P45 
for f in */*
do
    # we strip the path of the file from its filename
    # i.e. 'P45_input_foo/result.dat' will become 'P45_input_foo'
    newpath="${f%/*}"

    # mkdir -p /data/${newpath##*_} will create our new data structure
    # - /data/${newpath##*_} extract the last chain of character after a _, in our example, 'foo'
    # - mkdir -p will recursively create our structure
    # - cp "$f" "$_" will copy the file to our new directory. It will not launch if mkdir returns an error
    mkdir -p /data/${newpath##*_} && cp "$f" "$_"
done

${newpath##*_}${f%/*} 用法是 Bash 字符串操作方法的一部分。您可以阅读更多相关信息 here

一点 find 和一些 bash 技巧,下面的脚本可以为您完成技巧。请记住 运行 没有 mv 的脚本并查看 "/data/"$folder"/" 是否是您要移动文件的实际路径。

#!/bin/bash

while IFS= read -r -d '' file
do

    fileNew="${file%/*}"       # Everything before the last '\'
    fileNew="${fileNew#*/}"    # Everything after the last '\'

    IFS="_" read _ _ folder <<<"$fileNew"

    mv -v "$file"  "/data/"$folder"/"

done < <(find . -type f -name "result.dat" -print0)