0

I have files in format below:

abc_abc_abc   
abc_abc_abc.1    
abc_bca_bca    
abc_bca_bca.1    
abc_bca_bca.2    
abc_cab    
abc

I want to get the files which is having 2 underscores and exclude other files like with . (dot) and single underscore.

The result would look like:

abc_abc_abc
abc_bca_bca
2
  • What are you planning to use the filenames for? This matters as it may affect how one goes about generating them. Commented Jul 26, 2018 at 9:02
  • Could you potentially have a file named xyz_qrs_t.1 ? Commented Jul 26, 2018 at 12:10

3 Answers 3

4

You can use find:

find . -name "*_*_*" -not -name "*.*"

This will search in subdirectories also. If you don't want this, add -maxdepth 1 and maybe -type f if you only want regular files:

find . -maxdepth 1 -type f -name "*_*_*" -not -name "*.*"

Add -printf "%P\n" to get rid of the preceding ./.

0

With ksh, bash -O extglob or zsh -o kshglob using some double-negations (here assuming you also want to exclude files with 3 or more underscores):

printf '%s\n' !(!(*_*_*)|*_*_*_*|*.*)

With zsh -o extendedglob and its ~ except operator:

printf '%s\n' *_*_*~(*_*_*_*|*.*)

or using zsh's native negation operator:

printf '%s\n' ^(^*_*_*|*_*_*_*|*.*)

If you still want the files with more than 2 underscores, that's just !(!(*_*_*)|*.*) or *_*_*~*.* or ^(^*_*_*|*.*) in place of the above, respectively.

Other approaches could be !(*[._]*)_!(*[._]*)_!(*[._]*) (replace [_.] with . to allow 3 or more underscore).

0

Simplistically, in bash (or shells that support arrays:

files=(???_???_???)

This uses the ? globbing character to pick up files named as you've shown, with 3 characters, an underscore, 3 characters, an underscore, then 3 characters. This could be foiled if you have a filename such as xyz_qrs_t.1, though.

A little more refined would be:

files=([^._][^._][^._]_[^._][^._][^._]_[^._][^._][^._])

... which uses the [^ ... ] globbing syntax. Each [^._] asks for one character that is not a period or underscore. Mixed in there are two underscores, separating three batches of three [^._].

Loop over them with:

for f in "${files[@]}"; do printf "File: %s\n" "$f"; done

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.