How to only get file name with Linux 'find'?

后端 未结 10 1334
故里飘歌
故里飘歌 2020-11-28 18:19

I\'m using find to all files in directory, so I get a list of paths. However, I need only file names. i.e. I get ./dir1/dir2/file.txt and I want to get fi

相关标签:
10条回答
  • 2020-11-28 18:45

    Honestly basename and dirname solutions are easier, but you can also check this out :

    find . -type f | grep -oP "[^/]*$"
    

    or

    find . -type f | rev | cut -d '/' -f1 | rev
    

    or

    find . -type f | sed "s/.*\///"
    
    0 讨论(0)
  • 2020-11-28 18:56

    If you want to run some action against the filename only, using basename can be tough.

    For example this:

    find ~/clang+llvm-3.3/bin/ -type f -exec echo basename {} \; 
    

    will just echo basename /my/found/path. Not what we want if we want to execute on the filename.

    But you can then xargs the output. for example to kill the files in a dir based on names in another dir:

    cd dirIwantToRMin;
    find ~/clang+llvm-3.3/bin/ -type f -exec basename {} \; | xargs rm
    
    0 讨论(0)
  • 2020-11-28 18:59

    Use -execdir which automatically holds the current file in {}, for example:

    find . -type f -execdir echo '{}' ';'
    

    You can also use $PWD instead of . (on some systems it won't produce an extra dot in the front).

    If you still got an extra dot, alternatively you can run:

    find . -type f -execdir basename '{}' ';'
    

    -execdir utility [argument ...] ;

    The -execdir primary is identical to the -exec primary with the exception that utility will be executed from the directory that holds the current file.

    When used + instead of ;, then {} is replaced with as many pathnames as possible for each invocation of utility. In other words, it'll print all filenames in one line.

    0 讨论(0)
  • 2020-11-28 18:59

    As others have pointed out, you can combine find and basename, but by default the basename program will only operate on one path at a time, so the executable will have to be launched once for each path (using either find ... -exec or find ... | xargs -n 1), which may potentially be slow.

    If you use the -a option on basename, then it can accept multiple filenames in a single invocation, which means that you can then use xargs without the -n 1, to group the paths together into a far smaller number of invocations of basename, which should be more efficient.

    Example:

    find /dir1 -type f -print0 | xargs -0 basename -a
    

    Here I've included the -print0 and -0 (which should be used together), in order to cope with any whitespace inside the names of files and directories.

    Here is a timing comparison, between the xargs basename -a and xargs -n1 basename versions. (For sake of a like-with-like comparison, the timings reported here are after an initial dummy run, so that they are both done after the file metadata has already been copied to I/O cache.) I have piped the output to cksum in both cases, just to demonstrate that the output is independent of the method used.

    $ time sh -c 'find /usr/lib -type f -print0 | xargs -0 basename -a | cksum'
    2532163462 546663
    
    real    0m0.063s
    user    0m0.058s
    sys 0m0.040s
    
    $ time sh -c 'find /usr/lib -type f -print0 | xargs -0 -n 1 basename | cksum' 
    2532163462 546663
    
    real    0m14.504s
    user    0m12.474s
    sys 0m3.109s
    

    As you can see, it really is substantially faster to avoid launching basename every time.

    0 讨论(0)
提交回复
热议问题