带 for 循环的 Bash 递归函数

问题描述 投票:0回答:1

在根文件夹中,我有一个包含一些 mp3 文件的子文件夹结构。我想将所有子文件夹和 mp3 文件复制到 sd 卡,以便 mp3 播放器读取。简单地将整个根文件夹复制到卡上会打乱 mp3 文件的顺序。此问题已在互联网上有记录。一种解决方案是使用 rsync,这对我来说不起作用 - 另一种解决方案是一个接一个地复制文件,这样顺序就适合我的播放器。 因此,我编写了一个 bash 脚本来遍历我的子文件夹结构,在 SD 卡上创建一些子文件夹并将 mp3 文件复制到其中。由于我的子文件夹结构是随机的,我决定编写一个递归函数,在每个子文件夹中调用,如下所示:

ScanKo () 
{
  cd "$1"
  for i in *
  do
    if [[ -d "$i" ]]
    then
      mkdir -p "$2/$i"
      ScanKo "$1/$i" "$2/$i"
    elif [[ "${i##*.}" = "mp3" ]]
    then
      cp "$1/$i" "$2/$i"
    fi
  done
}

ScanKo "/home/monkey/source_root/" "/media/stick/destiny_root/"

函数 ScanKo 获取两个参数:源根文件夹和目标根文件夹。我 cd 进入源文件夹并使用 for 循环扫描所有内容。如果我点击一个子文件夹,我会在目标点(SD 卡)上创建这个子文件夹,并以子文件夹作为参数再次调用该函数。如果我点击一个 mp3 文件,我会将它复制到命运中。它仅在理论上有效。看起来,一旦子函数被调用,bash 就失去了它的上下文。

我通过递归过程实施相同的方法解决了这个问题。名为“sdMachen”的进程的相应 bash 脚本如下所示:

cd "$1"
for i in *
do
  if [[ -d "$i" ]]
  then
    mkdir -p "$2/$i"
    bash "$3/${0##*/}" "$1/$i" "$2/$i" "$3"
  elif [[ "${i##*.}" = "mp3" ]]
  then
    cp "$1/$i" "$2/$i"
  fi
done

我在命令行上使用三个参数调用脚本:

bash sdMachen "/home/monkey/source_root/" "/media/stick/destiny_root/" "$(pwd)"

我需要第三个参数,这样我就可以返回sdMachen所在的位置。部分

“$3/${0##*/}”

需要

,以便每次都能找到正确的 bash 脚本。基本上相当于

/脚本所在文件夹/sdMachen

它适用于递归过程 - 但为什么它不适用于递归 bash 函数?

bash for-loop recursion process
1个回答
0
投票

由于您使用的是 Bash,因此您可以受益于其

globstar
选项,将所有子目录作为平面列表进行使用:

#!/usr/bin/env bash

ScanKo() {
    local srcDir=${1:?}
    local dstDir=${2:?}

    # Validates arguments
    [ -d "$srcDir" ] && [ -d "$dstDir" ] || exit 2

    # Saves globstar and nullglob options
    if shopt -q globstar; then local gs=s; else local gs=u; fi
    if shopt -q nullglob; then local ng=s; else local ng=u; fi

    # Sets globstar and nullglob options
    shopt -s globstar nullglob

    # Iterates source directory hierarchy with globstar **
    for dir in "$srcDir/"**/; do
        mkdir -p -- "${dstDir%/}${dir##$srcDir}"
    done

    # Restores globstar and nullglob as they where
    shopt "-$gs" globstar
    shopt "-$ng" nullglob
}

ScanKo "$@"
© www.soinside.com 2019 - 2024. All rights reserved.