0

So I have a directory where I wish to open the only file in that directory that is human readable. I use file * to print the type of each file, and one file shows as ASCII-text. How can I redirect that specific file to cat or less to display its content?

EDIT:

Y'all are awesome. I'm trying each.

5 Answers5

2

You can use awk to search for files containing ASCII text:

less $(file * | awk -F: '$2 ~ "ASCII text" {print $1}')

This actually works also for directories containing several text files.

nohillside
  • 3,251
1

The following bash function will look through the files in the current directory; if exactly one of them reports back as being "ASCII text", then it will cat that file.

filecat() {
  local files=(./*)
  local count=0
  local filename=
  local f=
  for f in "${files[@]}"
  do
    if file "$f" 2>/dev/null | grep -q ": ASCII text$"
    then
      count=$((count + 1))
      filename="$f"
    fi
  done
  if [ "$count" -eq 1 ]
  then
    cat "$filename"
  fi
}
Jeff Schaller
  • 67,283
  • 35
  • 116
  • 255
1

Here's a safe way to open what file thinks are text files in the current directory in vim. Of course, you can change vim to echo to just print the names.

#!/bin/bash

for f in *; do
   out=$(file "$f")
   [[ "${out##*: }" =~ ASCII ]] && text_files+=("$f")
done

vim "${text_files[@]}"

exit

EDIT: use two # signs in the parameter expansion to handle filenames with a : in them.

m0dular
  • 1,261
1

With zsh, you could define a function like:

 istext() [[ $(file -b --mime-type -- "${1-$REPLY}") = text/* ]]

Which you could then use in glob qualifiers like:

 less -- *(.L+0+istext)

To view the non-empty (L+0 for length greater than 0) regular files (.) in the current directory that are text according to file.

0

To only less a file if it's an ASCII text:

less_if_text() {
   # $1 is the file name
   if file $1 | grep -q 'ASCII .* text' ; then
     less $1
   else
     echo "Not a text file: $1"
   fi
}

To list text files in a naive but easy to understand way:

ls_texts() {
  ls -a | while read filename; do 
    (file $filename | grep -q 'ASCII .* text') && echo $filename
  done
}

The above is not quite fast, though. A faster way would use file -f to avoid multiple file and grep invocations:

ls_texts() {
  ls | file -f - | egrep ':\s+ASCII .* text' | while read fname
    do cut -d ':' -f 1 
  done
}
9000
  • 1,639
  • If they already have the filename in hand ($1, the parameter to your function), then they could jus tpass it to cat or less themselves. Perhaps a more generic answer would run file on every file in the current (or given?) directory and go from there? – Jeff Schaller Mar 22 '18 at 17:51
  • @JeffSchaller: Updated the answer to include the listing of files. – 9000 Mar 22 '18 at 18:26
  • @JeffSchaller: Indeed, especially if you have file names with embedded spaces and other special characters; add --quote-names to alleviate it a bit. – 9000 Mar 22 '18 at 19:15