2

I'm using find to analyze a list of files. I want it to identify the files that are not ASCII files.

So this is what I've tried on the command line:

for me in `find 2022*`; do file -i $me | grep -L 'ascii'  ; done;

Output:

(standard input)
(standard input)
(standard input)
(standard input)
(standard input)
(standard input)
(standard input)

The number of standard input, which is 7, correctly indicates that it actually finds the right files out of the 200 submitted, but I need the name of the file itself.

How do I do this?

1

2 Answers 2

5

file is already printing the filename, you have to cut it after a simple grep. If your files are into the same directory:

file -i * | grep -v 'charset.*ascii' | cut -d: -f1

And if you match files into more subdirectories, into a bash shell:

shopt -s globstar
file -i 2022** | grep -v 'charset.*ascii' | cut -d: -f1

Or using find:

find 2022* -type f -exec sh -c 'file -i "$@" | grep -v 'ascii' | cut -d: -f1' sh {} +

There are some edge cases, the most probable could be a colon into a filename (: is used by file and grep to separate the filename from the rest) or filenames with newlines or a filename matching charset.*ascii while the file is not ascii. Here is another version to handle these cases also (assuming null separation supported):

file -00i * | awk -v RS='\0' -v ORS='\n' 'NF%2{f=$0;next} !/ascii/{print f}'

file with -00 puts a null byte at the end of the filename and at the end of the line. So we test only even lines, and if it doesn't match, we print the previous line (the filename).

4
  • 1
    this is assuming the filenames are nice enough to not contain newlines, colons, or strings that would match the pattern/string being looked for... could maybe build something out of file -i -b and find -exec {} \; if one wanted to fix that...
    – ilkkachu
    May 18 at 18:58
  • yes @ilkkachu and the more probable case could be a : into filenames, which is the common funny case for the grep output. For the matching pattern, it's good to add as much as we can.
    – thanasisp
    May 18 at 19:12
  • 1
    BSD file (which is the one most commonly used on most Linux distros) has a -0 (--print0) option. See the man page, but it's generally most useful to use it twice, e.g. -0 -0 or -00, so that it prints the filename, NUL, the desc, and another NUL for each file.
    – cas
    May 19 at 7:10
  • good point @cas. -0 and -z, -d $'\0' would handle the semicolon into filename case. I guess -00 to awk with null ORS and testing only even lines would handle any filenames and the case where a filename is named like charset_ascii but it's not ascii. (assuming GNU)
    – thanasisp
    May 19 at 7:37
2

You're piping data into grep's stdin, so grep does not have a filename to print.

I'm assuming 2022* are the filenames, not directories.

find . -type f -name '2022*' -exec sh -c '
    for file; do
        file -bi "$file" | grep -q ascii || echo "$file"
    done
' sh '{}' +
2
  • 1
    Use file -b to make it not print the filename, helps in case some file has ascii in the name... Also if I read it right, they wanted files that don't show up as "ascii" (grep -L prints names of the non-matching ones)
    – ilkkachu
    May 18 at 19:21
  • Thanks. Changed && to || to print the non-matching files. May 18 at 21:39

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.