Bash script: check if a file is a text file

I am writing a menu based bash script, one of the menu options is to send an email with a text file attachment. I am having trouble with checking if my file is a text file. Here is what I have:

fileExists=10
until [ $fileExists -eq 9 ]
do
  echo "Please enter the name of the file you want to attach: "
  read attachment
  isFile=$(file $attachment | cut -d -f2)
  if [[ $isFile = "ASCII" ]]
    then
      fileExists=0
    else
      echo "$attachment is not a text file, please use a different file"
  fi
done

I keep getting the error cut: delimiter must be a single character.

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

  1. From the fact that it says file $attachment
    rather than file "$attachment",
    I guess your script cannot handle filenames that contain spaces. 
    But, be advised that filenames can contain spaces,
    and well-written scripts can handle them.  Note, then:
    $ file "foo bar"
    foo bar:  ASCII text
    
    $ file "foo bar" | cut -d' ' -f2
    bar:

    One popular and highly recommended approach
    is to null-terminate the filenames:

    $ file -0 "foo bar" | cut -d $'' -f2
    :  ASCII text
  2. The file command makes educated guesses about
    what type of file a file is.  Guesses, naturally, are sometime wrong. 
    For example, file will sometimes look at an ordinary text file
    and guess that it is a shell script, C program, or something else. 
    So you don’t want to check whether the output from file is ASCII text,
    you want to see whether it says that the file is a text file. 
    If you look at the man page for file,
    you will see that it more-or-less promises
    to include the word text in its output if the file is a text file,
    but this might be in a context like shell commands text
    So, it may be better to check whether the output from file
    contains the word text:
    isFile=$(file -0 "$attachment" | cut -d $'' -f2)
    case "$isFile" in
       (*text*)
          echo "$attachment is a text file"
          ;;
       (*)
          echo "$attachment is not a text file, please use a different file"
          ;;
    esac

Method 2

The problem occurs in cut -d -f2. Change it to cut -d -f2.

To cut, the arguments look like this:

# bash: args(){ for i; do printf '%q \n' "$i"; done; }
# args cut -d -f2
cut 
-d -f2

And here is the problem. escaped the space to a space literal instead of a delimiter between arguments in your shell, and you didn’t add an extra space so the whole -d -f2 part appears as one argument. You should add one extra space so -d and -f2 appear as two arguments.

To avoid confusion, many people use quotes like -d' ' instead.

P.S.: Instead of using file and making everything ASCII, I’d rather use

if file "$attachment2" | grep -q text$; then
    # is text
else
    # file doesn't think it's text
fi

Method 3

I would circumvent the escaping and do:

... | cut -d' ' -f2

that way it is clear that you need a space between the delimiter character (specified by the three letters sequence ' ') and the following option. With -d -f2 it is easy to miss you should have done -d -f2.

Method 4

case $(file -b --mime-type - < "$attachment") in
  (text/*)
     printf '%sn' "$attachment is probably text according to file"
     case $(file -b --mime-encoding - < "$attachment") in
       (us-ascii) echo "and probably in ASCII encoding"
     esac
esac

Method 5

Another option is to not use cut and to match a regex against the full output of file:

#...
isFile=$(file $attachment)
if [[ "$var" =~ ^[^:]*: ASCII ]]
#...


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x