shell脚本遍历目录和拆分文件名

时间:2014-07-09 13:31:38

标签: bash shell unix

我需要从文件名中提取2件事 - 扩展名和数字。

我有一个文件夹" / var / www / html / MyFolder /",此文件夹包含更多文件夹,每个文件夹中都存有一些文件。 该文件具有以下结构:" a_X_mytest.jpg"或" a_X_mytest.png"。 " a _"是修复,并在每个文件夹中相同,我需要" X"和文件扩展名。

我的脚本如下所示:

#!/bin/bash
for dir in /var/www/html/MyFolder/*/
do
  dir=${dir%*/}
  find "/var/www/html/MyFolder/${dir##*/}/a_*.*" -maxdepth 1 -mindepth 1 -type f
done

这只是我脚本的开头。

我的剧本中有一个错误:

find: `/var/www/html/MyFolder/first/a_*.*': No such file or directory
find: `/var/www/html/MyFolder/sec/a_*.*': No such file or directory
find: `/var/www/html/MyFolder/test/a_*.*': No such file or directory

有人知道错误在哪里吗? 下一步,当上面的行正在工作时,将拆分找到的文件并获得这两部分。

分裂我会用这个:

arrFIRST=(${IN//_/ })
echo ${arrFIRST[1]}
arrEXT=(${IN//./ })
echo ${arrEXT[1]}

有人可以帮我解决问题吗?

2 个答案:

答案 0 :(得分:2)

<强> TL; DR:

您的脚本可以简化为以下内容:

for file in /var/www/html/MyFolder/*/a_*.*; do
  [[ -f $file ]] || continue
  [[ "${file##*/}" =~ _(.*)_.*\.(.*)$ ]] && 
    x=${BASH_REMATCH[1]} ext=${BASH_REMATCH[2]}
  echo "$x"
  echo "$ext"
done
  • 单个glob(文件名模式,通配符模式)就足够了,因为glob可以在层次结构的各个级别上有多个通配符 /var/www/html/MyFolder/*/a_*.*在文件夹a_*.*的任意直接子文件夹(*/)中找到与/var/www/html/MyFolder匹配的文件。
    您只需要find来匹配位于子树的不同级别的文件(但您可能还需要它来满足更复杂的匹配需求)。
  • [[ -f $file ]] || break确保只考虑文件,如果找不到匹配项,也会有效退出循环。
  • [[ ... =~ ... ]]使用bash的正则表达式匹配运算符=~从每个匹配文件(${file##*/})的文件名部分中提取感兴趣的标记。
  • 正则表达式匹配的结果存储在保留的数组变量"${BASH_REMATCH}"中,第一个元素包含捕获的第一个带括号的子表达式((...) - 又称捕获组),依此类推

    • 或者,您可以使用read数组将匹配的文件名解析为其组件:

      IFS='_.' read -ra tokens <<<"${file##*/}"
      x="${tokens[0]}"
      ext="${tokens[@]: -1}"
      

至于为什么你尝试过没有工作

  • find不支持将 globs 作为 filename 参数,因此它会逐字地解释"/var/www/html/MyFolder/${dir##*/}/a_*.*"
  • 此外,您必须将搜索的根文件夹 filename 模式分开,以在根文件夹的子树的任何级别上查找:
    • 根文件夹成为文件名参数
    • 通过-name-iname(不区分大小写的匹配)选项传递(始终引用)文件名模式
    • Ergo:find "/var/www/html/MyFolder/${dir##*/}" -name 'a_*.*' ...,类似于@konsolebox' answer

答案 1 :(得分:1)

我不确定所需的复杂性,但也许你想要的是

find /var/www/html/MyFolder/ -mindepth 2 -maxdepth 2 -type f -name 'a_*.*'

因此:

while IFS= read -r FILE; do
    # Do something with "$FILE"...
done < <(exec find /var/www/html/MyFolder/ -mindepth 2 -maxdepth 2 -type f -name 'a_*.*')

或者

readarray -t FILES < <(exec find /var/www/html/MyFolder/ -mindepth 2 -maxdepth 2 -type f -name 'a_*.*')
for FILE in "${FILES[@]}"; do
    # Do something with "$FILE"...
done