UNIX commands – find

command linefind

I'm trying to learn UNIX commands and I'm playing this game to learn and I'm really stuck at the moment. I'm in a server through ssh and the directory is full of random files and folders and the password for the next level is inside one of the files. I have been told that the file has the following attrbutes:

  • human-readable
  • 1033 bytes
  • non-executable

I am guessing that I should use the find command and I tried find ! -executable but that returned a load of files. The only human-readable help I can find in the manual or online is printing out the file sizes in human readable. So I'm a bit lost there?

Also I did try find ~ -size 1033b but that returned nothing. But when I tried find ~ -size -1033b it returned every file in the directory.

Best Answer

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).
Related Question