用于将文件夹名称复制并添加到多个子目录中的文件的Shell脚本

时间:2022-07-17 07:08:52

I have several folders with different images sharing file names, with a folder structure like this:

我有几个文件夹,不同的图像共享文件名,文件夹结构如下:

/parent/folder001/img001.jpg
/parent/folder001/img002.jpg
/parent/folder002/img001.jpg
/parent/folder002/img002.jpg
/parent/folder003/img001.jpg
/parent/folder003/img002.jpg
...

and would like to copy/rename these files into a new folder, like this:

并希望将这些文件复制/重命名为新文件夹,如下所示:

/newfolder/folder001_img001.jpg
/newfolder/folder001_img002.jpg
/newfolder/folder002_img001.jpg
/newfolder/folder002_img002.jpg
/newfolder/folder003_img001.jpg
/newfolder/folder003_img002.jpg
...

(It's probably better if newfolder isn't a subfolder of parent, since that might end up causing really weird recursion.)

(如果newfolder不是父文件夹的子文件夹,那可能会更好,因为这可能最终导致非常奇怪的递归。)

None of the folders containing images have any subfolders.

包含图像的文件夹都没有任何子文件夹。

Ideally, I'd like to be able to reuse the script to "update" newfolder, since I might need to add more folders-containing-images later along the line.

理想情况下,我希望能够重用该脚本来“更新”新文件夹,因为我可能需要在以后添加更多包含文件夹的图像。

How can I accomplish this with a shell script?

如何使用shell脚本完成此操作?

3 个解决方案

#1


3  

This is a bit tedious but will do:

这有点乏味但会做:

#!/bin/bash
parent=/parent
newfolder=/newfolder
mkdir "$newfolder"
for folder in "$parent"/*; do
  if [[ -d "$folder" ]]; then
    foldername="${folder##*/}"
    for file in "$parent"/"$foldername"/*; do
      filename="${file##*/}"
      newfilename="$foldername"_"$filename"
      cp "$file" "$newfolder"/"$newfilename"
    done
  fi
done

Put the parent path to parent variable and newfolder path to newfolder variable.

将父路径设置为父变量,将newfolder路径设置为newfolder变量。

#2


3  

functions to the rescue, updating Jahid's script:

救援功能,更新Jahid的脚本:

function updateFolder
{
    mkdir "$2"
    for folder in "$1"/*; do
    if [[ -d $folder ]]; then
        foldername="${folder##*/}"
        for file in "$1"/"$foldername"/*; do
            filename="${file##*/}"
            newfilename="$foldername"_"$filename"
            cp "$file" "$2"/"$newfilename"
        done
    fi
    done
}

used:

$ updateFolder /parent /newfolder

#3


2  

I would use something like this:

我会用这样的东西:

find -type f -exec sh -c 'f={}; fnew=$(rev <<< "$f" | sed 's~/~_~' | rev); echo "mv $f $fnew"' \;

This looks for files within the current directory structure and perform the following:

这将查找当前目录结构中的文件并执行以下操作:

  • get the file name
  • 获取文件名

  • replace the last / with _.
  • 用_替换最后一个/。

  • write echo "cp $old_file $new_file"
  • 写回声“cp $ old_file $ new_file”

Once you have run this and seen it prints the proper command, remove the echo so that it effectively does the mv command.

一旦你运行它并看到它打印正确的命令,删除回声,以便它有效地执行mv命令。

I know the fnew=$(rev <<< "$f" | sed 's~/~_~' | rev) is a bit ugly trick, but I couldn't find a better way to replace the last / with _. Maybe sed -r 's~/([^/]*)$~_\1~' could also be appropiate, but I always like using rev :)

我知道fnew = $(rev <<<“$ f”| sed's〜/ ~_~'| rev)是一个有点难看的伎俩,但我找不到更好的方法来替换最后一个/用_ 。也许sed -r的〜/([^ /] *)$ ~_ \ 1~'也可能是合适的,但我总是喜欢使用rev :)


Since your find does not behave well with the -sh c expression, let's use a while loop for it:

由于你的find在-sh c表达式中表现不佳,让我们使用while循环:

while read -r file
do
    new_file=$(rev <<< "$file" | sed 's~/~_~' | rev)
    echo "mv $file $new_file"; done < <(find . -type f)
done < <(find . -type f)

As a one-liner:

作为单线:

while read -r file; do new_file=$(rev <<< "$file" | sed 's~/~_~' | rev); echo "mv $file $new_file"; done < <(find . -type f)

#1


3  

This is a bit tedious but will do:

这有点乏味但会做:

#!/bin/bash
parent=/parent
newfolder=/newfolder
mkdir "$newfolder"
for folder in "$parent"/*; do
  if [[ -d "$folder" ]]; then
    foldername="${folder##*/}"
    for file in "$parent"/"$foldername"/*; do
      filename="${file##*/}"
      newfilename="$foldername"_"$filename"
      cp "$file" "$newfolder"/"$newfilename"
    done
  fi
done

Put the parent path to parent variable and newfolder path to newfolder variable.

将父路径设置为父变量,将newfolder路径设置为newfolder变量。

#2


3  

functions to the rescue, updating Jahid's script:

救援功能,更新Jahid的脚本:

function updateFolder
{
    mkdir "$2"
    for folder in "$1"/*; do
    if [[ -d $folder ]]; then
        foldername="${folder##*/}"
        for file in "$1"/"$foldername"/*; do
            filename="${file##*/}"
            newfilename="$foldername"_"$filename"
            cp "$file" "$2"/"$newfilename"
        done
    fi
    done
}

used:

$ updateFolder /parent /newfolder

#3


2  

I would use something like this:

我会用这样的东西:

find -type f -exec sh -c 'f={}; fnew=$(rev <<< "$f" | sed 's~/~_~' | rev); echo "mv $f $fnew"' \;

This looks for files within the current directory structure and perform the following:

这将查找当前目录结构中的文件并执行以下操作:

  • get the file name
  • 获取文件名

  • replace the last / with _.
  • 用_替换最后一个/。

  • write echo "cp $old_file $new_file"
  • 写回声“cp $ old_file $ new_file”

Once you have run this and seen it prints the proper command, remove the echo so that it effectively does the mv command.

一旦你运行它并看到它打印正确的命令,删除回声,以便它有效地执行mv命令。

I know the fnew=$(rev <<< "$f" | sed 's~/~_~' | rev) is a bit ugly trick, but I couldn't find a better way to replace the last / with _. Maybe sed -r 's~/([^/]*)$~_\1~' could also be appropiate, but I always like using rev :)

我知道fnew = $(rev <<<“$ f”| sed's〜/ ~_~'| rev)是一个有点难看的伎俩,但我找不到更好的方法来替换最后一个/用_ 。也许sed -r的〜/([^ /] *)$ ~_ \ 1~'也可能是合适的,但我总是喜欢使用rev :)


Since your find does not behave well with the -sh c expression, let's use a while loop for it:

由于你的find在-sh c表达式中表现不佳,让我们使用while循环:

while read -r file
do
    new_file=$(rev <<< "$file" | sed 's~/~_~' | rev)
    echo "mv $file $new_file"; done < <(find . -type f)
done < <(find . -type f)

As a one-liner:

作为单线:

while read -r file; do new_file=$(rev <<< "$file" | sed 's~/~_~' | rev); echo "mv $file $new_file"; done < <(find . -type f)