4

I have lots of files I'm searching through to try and find the ones that contain a string of 8 characters - nothing else.

So far I've tried: -

grep -x '.\{8,8\}'

Which is showing me files that contain a string of exactly 8 characters, but also show files that contain lots of other stuff as well as the 8 characters. I want the files that contain a string of exactly 8 characters and nothing more.

Any help would be much appreciated. Thanks.

  • 6
    All strings that are 9 (or more) bytes long contain strings of exactly 8 characters. Did you mean lines that are exactly 8 characters long (plus the newline), or files that contain lines like that, or files/lines that contain white-space separated "words" of exactly 8 characters, or something completely different? – ilkkachu May 22 '18 at 10:33
7

You are looking for files that are 9 bytes long, eight characters and a newline. This assumes that you are looking for single-byte characters only.

find . -type f -size 9c -exec grep -l -E '^.{8}$' {} +

This finds all regular files in or below the current directory that are exactly 9 bytes long. To verify that they only contain a single line, we run grep over them and try to match a line with exactly eight characters. We let grep output the names of the matching files with its -l option.

  • This is fantastic - you're a wizard! – crabsticks May 22 '18 at 10:31
  • That assumes all characters in all the files are single-byte. – Stéphane Chazelas May 22 '18 at 10:40
  • @StéphaneChazelas Yes, it does. I will add a note about this. – Kusalananda May 22 '18 at 10:42
  • 1
    @twalberg No. We have to make sure there are no other newlines in the file than at the end, otherwise we'd find a file whose contents is red\ncat\n\n for example. – Kusalananda May 22 '18 at 16:06
5

With GNU awk to find regular files that contain only one line, containing exactly 8 characters (not counting the newline character if any):

find . -type f -size +7c -size -50c -exec gawk '
  BEGINFILE               {p = 0}
  FNR == 1 && length == 8 {p = 1}
  FNR == 2                {p = 0; nextfile}
  ENDFILE                 {if (p) print FILENAME}' {} +

With find, we restrict to files whose size is in between 8 and 49 bytes. 8 for a file with 8 one-byte characters and no newline, 49 for 8 6-byte characters (the maximum in UTF-8, you may want to adapt for other charsets) and a newline.

Or with zsh:

has_one_line_of_8_characters() {
  local c
  ! read -ru0 -k10 c && [[ $c =~ $'^[^\n]{8}\n?$' ]]
} < ${1-$REPLY}

printf '%s\n' **/*(.DL+7L-50+has_one_line_of_8_characters)
1
gawk '/^.{9}$/{print FILENAME}' RS='\0' *

I chose 9 chars, because the 8 characters and the newline character in the end of line = 9 characters in total. If you need strictly 8 characters with the newline included, you should use the 8 number in the pattern.

Testing

I have four files in the test folder:

$ tail -n +1 -- *
==> 11_chars <==
zzzzzzzzzz

==> 5_chars <==
zzzz

==> 7_chars <==
zzzzzz

==> 9_chars <==
zzzzzzzz

Output

$ gawk '/^.{9}$/{print FILENAME}' RS='\0' *
9_chars

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.