How to understand and avoid non-interactive mode errors when running ispell from script?

591 Views Asked by At

Background

Ispell is a basic command line spelling program in linux, which I want to call for a previously collected list of file names. These file names are recursively collected from a latex root file for example. This is usefull when requiring to spell all recursively included latex files, and no other files. However, calling ispell from the command line turns out to be non-trivial as ispell gives errors of the form "Can't deal with non-interactive use yet." in some cases.

(As a side not, ideally I would like to call ispell programmatically from java using the ProcessBuilder class, and without requiring bash. The same error seems to pester this approach however.)

Question

Why is it that ispell gives the error "Can't deal with non-interactive use yet." in certain cases, when called in bash from a loop involving the read method, but not in other cases, as shown in the below code example?

The below minimal code example creates two small files (testFileOne.txt, testFileTwo.txt) and a file containing the paths of the two created files (testFilesListTemp.txt). Next, ispell is called for testFilesListTemp.txt in three different ways: 1. With the help of "cat" 2. By first collecting the names as a string, then looping over the substrings in the collected string, and calling ispell for each of them. 3. By looping over the contents of testFilesListTemp.txt directly, and calling ispell for the extracted paths.

For some reaons the third method does not work, and yields an error "Can't deal with non-interactive use yet.". Why exactly does this error occur, and how can it be prevented, and/or is there perhaps another variation of the third approach that would work without errors?

#!/bin/bash 

#ispell ./testFiles/ispellTestFile1.txt

# Creating two small files and a file with file paths for testing
printf "file 1 contents" > testFileOne.txt
printf "file 2 contents. With a spelling eeeeror." > testFileTwo.txt
printf "./testFileOne.txt\n./testFileTwo.txt\n" > testFilesListTemp.txt

COLLECTED_LATEX_FILE_NAMES_FILE=testFilesListTemp.txt


# Approach 1: produce list of file names with cat and 
# pass as argumentto ispell
# WORKS
ispell $(cat $COLLECTED_LATEX_FILE_NAMES_FILE)

# Second approach, first collecting file names as long string, 
# then looping over substrings and calling ispell for each one of them 
FILES=""
while read p; do
echo "read file $p" 
FILES="$FILES $p"
done < $COLLECTED_LATEX_FILE_NAMES_FILE

printf "files list: $FILES\n"

for latexName in $FILES; do
    echo "filename: $latexName" 
    ispell $latexName
done


# Third approach, not working 
# ispell compmlains in this case about not working in non-interactive 
# mode 
#: "Can't deal with non-interactive use yet."
while read p; do   
    ispell "$p" 
done < $COLLECTED_LATEX_FILE_NAMES_FILE 
1

There are 1 best solutions below

0
On

The third example does not work, because you redirect standard input. ispell needs a terminal and a user interaction. When you write code like this:

while read p; do   
    ispell "$p" 
done < $COLLECTED_LATEX_FILE_NAMES_FILE 

everything that is read from standard input by any program within the loop will be taken from the $COLLECTED_LATEX_FILE_NAMES_FILE file. ispell detects that and refuses operating. However, you can use "description redirection" to make read p read from the file, and ispell "$p" read from the "real" terminal. Just do:

exec 3<&0
while read p; do   
    ispell "$p" 0<&3
done < $COLLECTED_LATEX_FILE_NAMES_FILE 

exec 3<&0 "copies" (saves) your standard input (0, the "terminal") to descriptor 3. And later on you redirect standard input (0) to ispell from that descriptor, by typing 0<&3 (you can omit 0 if you like).