Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
获取不同的扩展列表Linux_Linux_Shell_Awk - Fatal编程技术网

获取不同的扩展列表Linux

获取不同的扩展列表Linux,linux,shell,awk,Linux,Shell,Awk,我是Linux新手,目前面临一个问题。我想从文件夹中获取扩展名列表(.doc、.pdf)。我在谷歌上搜索了很多,最后我得到了一个解决方案,如下所示: find . -type f | awk -F. '!a[$NF]++{print $NF}' 我理解find-键入f,但无法理解awk-f![$NF]+{print$NF}'这是什么意思 NF=当前记录中的字段数 有人能解释一下吗 提前感谢。为此,您可以使用以下命令: $find <DIR> -type f -print0 | x

我是Linux新手,目前面临一个问题。我想从文件夹中获取扩展名列表(.doc、.pdf)。我在谷歌上搜索了很多,最后我得到了一个解决方案,如下所示:

 find . -type f | awk -F. '!a[$NF]++{print $NF}'
我理解
find-键入f,但无法理解awk-f![$NF]+{print$NF}'
这是什么意思

NF=当前记录中的字段数

有人能解释一下吗


提前感谢。

为此,您可以使用以下命令:

$find <DIR> -type f -print0 | xargs -0 -n1 basename | grep -Po '(?<=.)\..*$' | sort | uniq 
.bak
.c
.file
.file.bak
.input
.input.bak
.log
.log.bak
.out
.out.bak
.test
.test.bak
.txt
.txt.bak

为此,可以使用以下命令:

$find <DIR> -type f -print0 | xargs -0 -n1 basename | grep -Po '(?<=.)\..*$' | sort | uniq 
.bak
.c
.file
.file.bak
.input
.input.bak
.log
.log.bak
.out
.out.bak
.test
.test.bak
.txt
.txt.bak

一种非常简单的方法是对输出进行排序,只保留唯一的扩展,例如

find . -type f -regex ".*[.][a-zA-Z0-9][a-zA-Z0-9]*$" | \
awk -F '.' '{ print $NF }' | sort -u
如果您的
排序
不支持
-u
选项,则可以将
排序
的结果传送到
uniq
,例如

find . -type f -regex ".*[.][a-zA-Z0-9][a-zA-Z0-9]*$" | \
awk -F '.' '{ print $NF }' | sort | uniq
-regex
选项将
find
选择限制为至少具有一个ASCII字符扩展名的文件名。但是,如果文件包含
”,它也会拾取没有扩展名的文件。
,例如
foo.bar.fatcat
将导致列表中包含
fatcat

您可以调整正则表达式以满足需要。如果您的
find
版本支持posix扩展正则表达式,那么您可以防止拾取更长的扩展。例如,要将扩展名限制为
1-3
个字符,可以使用:

find . -type f -regextype posix-extended -regex ".*[.][a-zA-Z0-9]{1,3}$" | \
awk -F '.' '{ print $NF }' | sort -u

有其他方法可以实现这一点,但鉴于您最初的示例,这是一个很好的后续操作。

一个非常简单的方法是对输出进行排序,只保留唯一的扩展,例如

find . -type f -regex ".*[.][a-zA-Z0-9][a-zA-Z0-9]*$" | \
awk -F '.' '{ print $NF }' | sort -u
如果您的
排序
不支持
-u
选项,则可以将
排序
的结果传送到
uniq
,例如

find . -type f -regex ".*[.][a-zA-Z0-9][a-zA-Z0-9]*$" | \
awk -F '.' '{ print $NF }' | sort | uniq
-regex
选项将
find
选择限制为至少具有一个ASCII字符扩展名的文件名。但是,如果文件包含
”,它也会拾取没有扩展名的文件。
,例如
foo.bar.fatcat
将导致列表中包含
fatcat

您可以调整正则表达式以满足需要。如果您的
find
版本支持posix扩展正则表达式,那么您可以防止拾取更长的扩展。例如,要将扩展名限制为
1-3
个字符,可以使用:

find . -type f -regextype posix-extended -regex ".*[.][a-zA-Z0-9]{1,3}$" | \
awk -F '.' '{ print $NF }' | sort -u

有其他方法可以实现这一点,但鉴于您最初的示例,这是一个密切的后续问题。

要回答您的问题,awk行正在做什么:

正如您已经指出的,行
find-键入f
返回位于当前目录中的文件列表。例如

./foo.ext1
./bar.ext2
./spam.ext2
./ham.ext3
./spam.ham.eggs
此文件列表通过管道发送到命令
awk-F!一个[$NF]+{print$NF}'
。此awk行包含大量信息。首先,您需要知道awk是一个记录解析器,其中每个记录都由多个字段组成。默认记录为
,而默认字段分隔符为空格序列。那么,您的awk生产线现在做了什么:

  • -F.
    ::这将字段分隔符重新定义为点(
    )。从这一点开始,示例中的所有行现在都有2个字段(例如第1行
    foo
    ext1
    ),而最后一行有3个字段(
    spam
    ham
    eggs
  • NF
    ::这是一个
    awk
    变量,返回每个记录的字段数。很明显,扩展名由最后一个字段(
    $NF
    )表示
  • a[$NF]
    :这是一个数组,其中索引是扩展名。默认数组值为
    ,除非您为其赋值
  • a[$NF]+
    ::返回
    a[$NF]
    的当前值,并在返回后用1递增该值。因此,对于第1行,
    a[“ext1”]++
    返回
    0
    ,并将
    a[“ext1”]
    设置为
    1
    。而对于第3行,
    a[“ext2”]++
    返回
    1
    ,并将
    a[“ext2”]
    设置为
    2
    。这表示
    a[$NF]
    跟踪出现
    $NF
    的次数

  • !a[$NF]+
    :这结合了上述逻辑,但检查
    a[$NF]+
    的返回值是否为
    0
    。如果是
    0
    ,则返回
    true
    ,否则返回
    false
    。对于示例的第
    2行
    ,此语句将返回
    true
    ,因为
    a[“ext2”]+
    具有值
    0
    。但是,在语句
    之后,[“ext2”]
    的值为1。读取第3行时,语句将返回
    false
    。换句话说,我们已经看到
    $NF
    了吗?当你用“是”或“否”回答这个问题时,用一增加
    $NF
    的计数

  • !一个[$NF]+{print$NF}
    ::这个组合了一切。它本质上表示,如果
    ![$NF]+
    返回
    true
    ,然后
    打印$NF
    ,但在打印之前,增量
    a[$NF]
    。或者换句话说,如果表示扩展名的字段(
    $NF
    )第一次出现,请打印该字段。如果它以前已经出现过,
    什么也不做

数组的递增很重要,因为它跟踪已经看到的内容。因此,一行一行地发生以下情况

foo.ext1       => $NF="ext1", a["ext1"] is 0 so print $NF and set a["ext1"]=1
bar.ext2       => $NF="ext2", a["ext2"] is 0 so print $NF and set a["ext2"]=1
spam.ext2      => $NF="ext2", a["ext2"] is 1 so do not print and set a["ext2"]=2
ham.ext3       => $NF="ext3", a["ext3"] is 0 so print $NF and set a["ext3"]=1
spam.ham.eggs  => $NF="eggs", a["eggs"] is 0 so print $NF and set a["eggs"]=1
输出是

ext1
ext2
ext3
eggs
一般评论:

  • 没有扩展名或不在隐藏目录中的文件(例如,没有扩展名的
    /path/to/awesome\u filename\u
    /path/to/.secret/filename\u
    )或其完整路径的一部分,打印时就好像它是扩展名一样。然而,结果是没有意义的,即

    /path/to/awesome_filename_without_extension
    secret/awesome_filename_without_extension
    
    最好通过以下方式解决此问题:

    find . -type f -exec  basename -a '{}' + \
      | awk -F. '((NF>1)&&(!a[$NF]++)){print $NF}'