I am trying to find an efficient way to do the level 5 of the OverTheWire bandit challenge.

Anyway, I have a bunch of files, and there is only one that respects the following criteria:

  • Human-readable
  • 1033 bytes in size
  • Non-executable

Right now, I am using the find command, and I am able to find the files matching the 2 last criteria:

find . -size 1033c ! -executable

However, I don't know how to excluse non-human-readable files. Solutions I found for that challenge use the -readable test parameter, but I don't think this works. -readable only looks at the files' permissions, and not at its content, while the challenge description ask for an ASCII file or something like that.

  • 1
    How do you define human readable? Not binary?
    – terdon
    Sep 30 '16 at 13:51
  • 2
    file command is your friend :) Sep 30 '16 at 13:52
  • Maybe duplicate of: stackoverflow.com/questions/14505218/…
    – zuazo
    Sep 30 '16 at 13:55
  • 3
    Humans are one of the most intelligent known species on earth. They're also the only one known to versed with computers. They can read most files provided they can find out the type and get hold of the encryption keys for encrypted one. Sep 30 '16 at 13:58
  • 2
    – Dan Bolser
    May 2 '19 at 15:03

13 Answers 13


Yes, you can use find to look for non-executable files of the right size and then use file to check for ASCII. Something like:

find . -type f -size 1033c ! -executable -exec file {} + | grep ASCII

The question, however, isn't as simple as it sounds. 'Human readable' is a horribly vague term. Presumably, you mean text. OK, but what kind of text? Latin character ASCII only? Full Unicode? For example, consider these three files:

$ cat file1
$ cat file2
$ cat file3
$ cat file4
echo foo

These are all text and human readable. Now, let's see what file makes of them:

$ file *
file1: ASCII text
file2: UTF-8 Unicode text
file3: UTF-8 Unicode text
file4: POSIX shell script, ASCII text executable

So, the find command above will only find file1 (for the sake of this example, let's imagine those files had 1033 characters). You could expand the find to look for the string text:

find . -type f -size 1033c ! -executable -exec file {} + | grep -w text

With the -w, grep will only print lines where text is found as a stand-alone word. That should be pretty close to what you want, but I can't guarantee that there is no other file type whose description might also include the string text.


While -exec is mostly used to do something with the files that where found, it can also act as a test. Therefore, we can add it to your other criteria:

find . \
  -size 1033c \
  -not -executable \
  -exec sh -c 'file {} | grep "text$"' \;

Remember, grep returns non-zero when the pattern wasn't found, and sh -c "COMMAND" will return the result of the evaluation (as long as it's valid). So this will only print files where file <filename> spits something out that ends with text, e.g. "UTF-8 Unicode text` or "ASCII text", but not "Non-ISO extended-ASCII text, with escape sequences".

In a single line, it even ends up shorter than going over xargs:

find . -size 1033c -not -executable -exec sh -c 'file {} | grep "text$"' \;

Keep in mind that you can replace sh -c 'file {} | grep "text$"' with any custom command. If you want to check for something very complex, it might be a better idea to provide a shell script and use that instead:

find . -size 1033c -not -executable -exec is_human_readable.sh {} \;

which, in the long run, is easier to maintain than your shell's history:

file "$@" | grep "text$" > /dev/null
  • Nice! Note, however, that matching text$ will exclude things recognized as shell scripts. Anything with a shebang is identified as a script, and those are perfectly human readable.
    – terdon
    Sep 30 '16 at 14:39
  • @terdon true, but scripts tend to be executable :D. That being said, a proper script should also recognize PDFs. But on the other hand, is a PDF containing an image human readable? Is a PNG of some text readable? Probably. I guess a complet test will be… challenging.
    – Zeta
    Sep 30 '16 at 14:43

You only need to use:

find inhere -size 1033c

It will give you the only file that contains the password.

  • why does +1033c return more files? is that like a greater-or-equals sign-?
    – szeitlin
    Aug 29 '19 at 20:49
find . -size 1033c ! -executable -exec file {} +

Just run the following against the contents of the directory:

$ file -- *
-file00: data
-file01: data
-file02: data
-file03: data
-file04: data
-file05: data
-file06: data
-file07: ASCII text
-file08: data
-file09: data
$ cat -- \-file07

There is only 1 file with 1033 bytes of size.

bandit5@bandit:~$ find -size 1033c

Why 1033c and not 1033? Check the man page

   -size n[cwbkMG]
          File uses n units of space, rounding up.  The following suffixes can be used:

          `b'    for 512-byte blocks (this is the default if no suffix is used)

          `c'    for bytes

          `w'    for two-byte words

          `k'    for Kilobytes (units of 1024 bytes)

          `M'    for Megabytes (units of 1048576 bytes)

          `G'    for Gigabytes (units of 1073741824 bytes)

Verify it with ls -l and file command, and you get all the answer.

bandit5@bandit:~$ ls -l ./inhere/maybehere07/.file2
-rw-r----- 1 root bandit5 1033 May  7 20:15 ./inhere/maybehere07/.file2
bandit5@bandit:~$ file ./inhere/maybehere07/.file2
./inhere/maybehere07/.file2: ASCII text, with very long lines
  1. human-readable (ASCII text)
  2. 1033 bytes in size (Also in ls -l output)
  3. not executable (-rw-r-----)
find . -size 1033c ! -executable|xargs file|grep "ASCII text" |awk -F: '{print $1}'

Please try this combined commands. it works on my station.


You can try this

find . -size 1033c ! -executable -exec file {} +

Your challenge does not allows grep. password file will be reported as "ASCII text, with very long lines"


To filter out the human-readable file names, you can make use of the [:print:] (printable) character class name. You will find more about such classes in the manual for grep.

find . -type f -size 1033c -name "[[:print:]]*" ! -executable

On a second thought, the "human-readable" requirement might refer to the file's content, instead of its name. In other words, you would be searching for text files. That is a little more tricky. As @D_Bye suggested in a comment, you should then use the file command to determine the file content type. But it would not be a good idea to run file after a pipe, because it would complicate the task of displaying the file's name. Here's what I suggest:

find . -type f -size 1033c ! -executable -exec sh -c 'file -b $0 | grep -q text' {} \; -print

This is briefly how the file-part works:

  • The -exec predicate executes sh -c 'file -b $0 | grep -q text' FILENAME for each FILENAME that satisfies all the previous conditions (type, size, non-executable).
  • For each of those files, a shell (sh) runs this short script: file -b $0 | grep -q text, replacing $0 with the filename.
  • The file program determines the content type of each file and outputs this information. The -b option prevents printing the name of each tested file.
  • grep filters the output coming from file program, searching for lines containing "text". (See for yourself, how a typical output of the file command looks like.)
  • But grep does not output the filtered text, because it has the -q (quiet) option given. What it does, is just change its exit status to either 0 (which represents "true" - the filtered text was found) or 1 (meaning "error" - the text "text" did not appear in the output from file).
  • The true/false exit status coming from grep is passed further by sh to find and acts as the final result of the whole "-exec sh -c 'file $0 | grep -q text' {} \;" test.
  • In case the above test returned true, the -print command is executed (i.e. the name of the tested file is printed).
bandit4@bandit:~$ ls

bandit4@bandit:~$ file inhere/*

inhere/-file00: data
inhere/-file01: data
inhere/-file02: data
inhere/-file03: data
inhere/-file04: data
inhere/-file05: data
inhere/-file06: data
inhere/-file07: ASCII text
inhere/-file08: data
inhere/-file09: data

bandit4@bandit:~$ pwd 


bandit4@bandit:~$ cat /home/bandit4/inhere/-file07

  • Simply use file inhere/* and cat /home/bandit4/inhere/-file07
    – user234732
    Jun 5 '17 at 22:41
find  -type f ! -executable -size 1033c

will get you the file from the exercise

find . -type f -size 1033c ! -executable | xargs file | grep text

Fan of one liners


I think the longer way of finding the password for this bandit level mentioned by most above using find and grep is the most descriptive command.

find . -type f -size 1033c ! -executable -exec file {} + | grep ASCII

But, after using the 'file' command more I realized its quite easy to locate human-readable files (aka ASCII in this level) this way by checking an entire directories file types. The inhere directory holds files with name '-filexx' or quickly check the entire inhere directory with file ./*

Here was my approach.

bandit4@bandit:~/inhere$ file ./*
./-file00: data
./-file01: data
./-file02: data
./-file03: data
./-file04: data
./-file05: data
./-file06: data
./-file07: ASCII text
./-file08: data
./-file09: data

bandit4@bandit:~/inhere$ cat ./-file07

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