31

使用 bash,如何在没有解释器抱怨的情况下获取文件夹中的文件数量,不包括 shell 脚本中的目录?

在朋友的帮助下,我试过了

$files=$(find ../ -maxdepth 1 -type f | sort -n)
$num=$("ls -l" | "grep ^-" | "wc -l")

从命令行返回:

../1-prefix_blended_fused.jpg: No such file or directory
ls -l :  command not found
grep ^-: command not found
wc -l:   command not found

分别。这些命令适用于命令行,但不适用于 bash 脚本。

给定一个填充了格式为 的图像文件的文件1-pano.jpg,我想抓取目录中的所有图像以获取最大编号的文件以附加到正在处理的下一个图像上。

为什么会出现差异?

4

10 回答 10

43

引号导致错误消息。

要获取目录中的文件数:

shopt -s nullglob
numfiles=(*)
numfiles=${#numfiles[@]}

它创建一个数组,然后用其元素的计数替换它。这将包括文件和目录,但不包括点文件或...或其他点目录。

使用nullglob这样一个空目录会给出 0 而不是 1 的计数。

您可以改为使用find -type f,也可以计算目录并减去:

# continuing from above
numdirs=(*/)
numdirs=${#numdirs[@]}
(( numfiles -= numdirs ))

另请参阅“如何在目录中找到最新(最新、最早、最旧)的文件?

您可以在执行块内拥有任意数量的空格。它们通常有助于提高可读性。唯一的缺点是它们使文件稍大一些,并且可能会(仅)稍微减慢初始解析。有一些地方必须有空格(例如 around [, [[, ], ]]and =in comparisons)和一些必须没有空格的地方(例如 around=在一个 assignment.

于 2012-06-21T04:21:12.633 回答
19
ls -l | grep -v ^d | wc -l

一条线。

于 2015-07-22T03:50:02.693 回答
16

怎么样:

count=$(find .. -maxdepth 1 -type f|wc -l)
echo $count
let count=count+1 # Increase by one, for the next file number
echo $count

请注意,此解决方案效率不高:它为findandwc命令生成子 shell,但它应该可以工作。

于 2012-06-21T05:37:37.427 回答
3

file_num=$(ls -1 --file-type | grep -v '/$' | wc -l)

这比 find 命令轻了一点,并且计算当前目录的所有文件。

于 2012-06-21T07:55:56.050 回答
2

我能想到的最直接、最可靠的方法是使用该find命令来创建可靠的可数输出。

计算findwith的字符输出wc

find . -maxdepth 1 -type f -printf '.' | wc --char

或输出的字符串长度find

a=$(find . -maxdepth 1 -type f -printf '.')
echo ${#a}

或使用find输出来填充算术表达式:

echo $(($(find . -maxdepth 1 -type f -printf '+1')))
于 2019-08-25T13:06:59.540 回答
1

简单有效的方法:

#!/bin/bash
RES=$(find ${SOURCE} -type f | wc -l)
于 2014-09-11T15:37:03.813 回答
1

摆脱引号。shell 将它们视为一个文件,因此它正在寻找“ls -l”。

于 2012-06-21T03:13:54.227 回答
0

删除qoutes,你会没事的

于 2012-06-21T03:17:14.730 回答
0

这是您可以将其作为函数执行的一种方法。注意:你可以传递这个例子,dirs 表示(目录计数),files 表示文件计数或“all”表示目录中所有内容的计数。不遍历树,因为我们不想这样做。

function get_counts_dir() {

    # -- handle inputs (e.g. get_counts_dir "files" /path/to/folder)
    [[ -z "${1,,}" ]] && type="files" || type="${1,,}"
    [[ -z "${2,,}" ]] && dir="$(pwd)" || dir="${2,,}"

    shopt -s nullglob
    PWD=$(pwd)
    cd ${dir}

    numfiles=(*)
    numfiles=${#numfiles[@]}
    numdirs=(*/)
    numdirs=${#numdirs[@]}

    # -- handle input types files/dirs/or both
    result=0
    case "${type,,}" in
        "files")
            result=$((( numfiles -= numdirs )))
        ;;
        "dirs")
            result=${numdirs}
        ;;
        *)  # -- returns all files/dirs
            result=${numfiles}
        ;;

    esac

    cd ${PWD}
    shopt -u nullglob

    # -- return result --
    [[ -z ${result} ]] && echo 0 || echo ${result}
}

使用函数的例子:

folder="/home"
get_counts_dir "files" "${folder}"
get_counts_dir "dirs" "${folder}"
get_counts_dir "both" "${folder}"

将打印如下内容:

2
4
6
于 2019-02-28T16:48:32.417 回答
0

扩展接受的答案(Dennis W):当我尝试这种方法时,在 Bash 4.4.5 中没有子目录的目录计数不正确。

问题是,默认情况下,Bash 中没有设置 nullglob,而是numdirs=(*/)使用 glob 模式设置了一个 1 元素数组*/。同样,我怀疑numfiles=(*)空文件夹会有 1 个元素。

设置shopt -s nullglob禁用 nullglobbing 为我解决了这个问题。有关为什么在 Bash 上默认未设置 nullglob 的精彩讨论,请参见此处的答案:为什么 nullglob 不是默认设置?

注意:我会直接评论答案,但缺乏声誉点。

于 2017-02-25T15:50:16.707 回答