【问题标题】:Get file from current directory and print in the same line there files with same extension从当前目录获取文件并在同一行打印具有相同扩展名的文件
【发布时间】:2017-09-29 05:56:56
【问题描述】:

脚本应该列出当前目录下除后缀的文件(并以不带后缀的形式结束列表)。

示例(也称为“.extension:”)

.c: first.c main.c var.c
.h: const.h first.h
.odt: relazione.odt
makefile README COPYING

我正在尝试使用 ls、sort、uniq,但我做不到。 有人可以帮助我吗?

我用python写了一个解决方案:

#!/usr/bin/env python3
import os

dictionary={}

for dirpath,_,files in os.walk("./"):
    for f in files:
        path = os.path.abspath(os.path.join(dirpath, f))
        _ , ext = os.path.splitext(path)
        if ext not in dictionary:
            dictionary[ext] = []
        dictionary[ext].append(f)

for k in dictionary:
    if k != "":
        print(k, end=": ")
        for i in dictionary.get(k):
            print(i, end= " ")
        print("")

for i in dictionary.get(""):
    print(i, end= " ")
print("")

【问题讨论】:

  • 你能告诉我们你的尝试吗?
  • 我试过这个以获得后缀 ls |排序-t。 | awk -F '.' '{if (NF>1) {print $NF}}'

标签: bash shell awk command-line


【解决方案1】:

给定:

$ ls -lndp *
-rw-r--r--  1 501  0   0 May  1 15:01 COPYING
-rw-r--r--  1 501  0   0 May  1 15:01 README
-rw-r--r--  1 501  0   0 May  2 06:36 a.b.c
drwxr-xr-x  2 501  0  68 May  2 06:15 adir.dir/
-rw-r--r--  1 501  0   0 May  1 15:00 const.h
-rw-r--r--  1 501  0   0 May  2 08:00 file name with a space.doc
-rw-r--r--  1 501  0   0 May  1 15:00 first.c
-rw-r--r--  1 501  0   0 May  1 15:00 first.h
-rw-r--r--  1 501  0   0 May  1 15:00 main.c
-rw-r--r--  1 501  0   0 May  1 15:01 makefile
-rw-r--r--  1 501  0   0 May  1 15:01 relazione.odt
-rw-r--r--  1 501  0   0 May  1 15:00 var.c

假设您不想包含目录,您可以过滤掉目录并将文件名提供给awk

awk '{n=split($0, parts, /\./)
      ext = ( n>1 ? parts[n] : "none" )
      ext2files[ext] = ext2files[ext] OFS $0
      }
   END{
      for (ext in ext2files) 
         print ext ":" ext2files[ext]
      }' <(for fn in *; do  [ ! -d "$fn" ] && echo "$fn"; done)
h: const.h first.h
none: COPYING README makefile
odt: relazione.odt
doc: file name with a space.doc
c: a.b.c first.c main.c var.c

如果你想对输出进行排序,并且你有gawk,你可以编写一个比较函数:

gawk ' function cmp_idx(i1, v1, i2, v2) {
         if (i1=="" || i2=="")
            return (i1=="") ? 1 : -1 
         return (i1 < i2) ? -1 : (i1 != i2)
      }
      {
      n=split($0, parts, /\./)
      ext = ( n>1 ? parts[n] : "" )
      ext2files[ext] = (ext2files[ext] ? ext2files[ext] OFS $0 : $0)
      }
   END{
      PROCINFO["sorted_in"] = "cmp_idx"
      for (ext in ext2files) 
         print (ext ? ext ": " ext2files[ext] : ext2files[ext])
      }' <(for fn in *; do  [ ! -d "$fn" ] && echo "$fn"; done)
c: a.b.c first.c main.c var.c
doc: file name with a space.doc
h: const.h first.h
odt: relazione.odt
COPYING README makefile

【讨论】:

  • “none files”必须放在底部,没有前缀“none:”
【解决方案2】:
#!/bin/bash
ls -d *.* 2>/dev/null | cut -d. -f2- | sort -u | while read i ; do
    echo -n ."$i":' '
    for j in *."$i" ; do
         echo -n "$j"' '
    done
    echo
done
ls | grep -v '\.' | tr '\n' ' '

【讨论】:

    【解决方案3】:
    awk '
    BEGIN {
        for (i=1; i<ARGC; i++) {
           fname = ARGV[i]
           n = split(fname,parts,/\./)
           ext = ( n>1 ? parts[n] : "none" )
           ext2files[ext] = ext2files[ext] OFS fname
        }
        for (ext in ext2files) {
            print ext ":" ext2files[ext]
        }
        exit
    }' *
    

    【讨论】:

    • 不想列出目录吗?
    • 帖子被标记为 Bash Shell Awk 命令行 在这种情况下——这是正确答案。顺便说一句,我是 Perl 粉丝。
    • @EdMorton: 需要split(fname,parts,/\./) 才能在文字上拆分.
    • @dawg 是的,你说得对,谢谢。我没想到,因为 split() 的第三个参数是字段分隔符(如FS),并且在字段分隔符中,任何单个字符都按字面意思处理,但是当第三个参数是字符串(动态正则表达式)时,该功能适用​​,不是我写的正则表达式文字。在这种情况下,使用 "." 会产生与 /./ 不同的结果。
    • @123 是的,它会列出目录并且不会列出以. 开头的文件,我希望 OP 会告诉我们是否有任何问题。
    【解决方案4】:

    可以使用 Perl。

    use warnings;
    use strict;
    
    die "Too many args. Please supply one directory\n" if @ARGV > 1;
    die "Too few args. Please supply one directory\n" if @ARGV < 1;
    
    opendir (my $dir, "$ARGV[0]") || die "$ARGV[0]: $!\n" ;
    my %extfiles;
    my @Others;
    while (my $file = readdir $dir){
            next if (-d "./$file");
            if($file =~ /^..*(\.[^\.]*)$/){
                    $extfiles{$1}=$extfiles{$1}?"$extfiles{$1} $file":"$file"
            }
            else{
                    push @Others,$file
            }
    }
    closedir $dir;
    
    #print "Files with extensions\n\n";
    for my $extension (keys %extfiles){
            print "$extension: $extfiles{$extension}\n";
    }
    
    #print "\nFiles without extensions\n\n";
    
    print join (" ",@Others),"\n";
    

    保存在文件中,例如

    ListExt.pl
    

    运行方式:

    perl ListExt.pl $Dir
    

    【讨论】:

      【解决方案5】:

      您可以使用这个find + awk 脚本:

      find . -maxdepth 1 -type f -print0 |
      awk -v RS='\0' -F. '{$0 = substr($0, 3)} NF>1{ext[$NF] = ext[$NF] OFS $0; next}
      {noext = noext $0 OFS} END{for (e in ext) print "." e ":" ext[e]; print noext}'
      

      【讨论】:

      • 你能解释一下你在这个脚本中做了什么吗?它只适用于它找到的第一个文件
      • 我已经用一个包含数百个文件的目录对其进行了测试,它工作正常。它使用 awk 的关联数组来创建以索引为每个文件的扩展名的数组。
      • @anubhava 取决于它是什么 awk,很确定一些旧的不能将空字符作为 RS。
      • @123 你说得对,我有“mawk 1.3.3 Nov 1996,版权所有 (C) Michael D. Brennan”我现在安装“GNU Awk 4.1.1”和 (@)anubhava 脚本作品
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-13
      • 2017-08-31
      • 1970-01-01
      • 1970-01-01
      • 2021-06-08
      • 1970-01-01
      相关资源
      最近更新 更多