V-Red
V-Red

Reputation: 249

Read a file line-by-line on bash; each line containing the path to another unqiue file

Each line in a given file 'a.txt' contains the directory/path to another unique file. Suppose we want to parse 'a.txt' line-by-line, extract the path in string format, and then use a tool such as vim to process the file at this path, and so on.

After going through this thread - Read a file line by line assigning the value to a variable, I wrote the following script, say 'open-file.sh' on bash (I'm new to it)

#!/bin/bash
while IFS='' read -r line || [[ -n "$line" ]]; do
  vim -c ":q" -cq $line # Just open the file and close it using :q 
done < "$1"

We would then run the above script as -

./open-file.sh a.txt

The problem is that although the path to a new file is correctly specified by $line, when vim opens the file, vim continues to receive the text contained in 'a.txt' as a command. How can I write a script where I can correctly obtain the path from 'a.txt', open it using vim, and then continue parsing the remaining lines in 'a.txt' ?

Upvotes: 2

Views: 619

Answers (3)

Socowi
Socowi

Reputation: 27245

The problem was already mentioned in a comment under the answer you based your script on.

vim is consuming stdin which is given to the loop by done < $1. We can observe the same behavior in the following example:

$ while read i; do cat; done < <(seq 3)
2
3

<(seq 3) simulates a file with the three lines 1, 2, and 3. Instead of three silent iterations we get only one iteration and the output 2 and 3.

stdin is not only passed to read in the head of the loop, but also to cat in the body of the loop. Therefore read reads one line, the loop is entered, cat reads all remaining lines, stdin is empty, read has nothing to read anymore, the loop exits.

You could circumvent the problem by redirecting something to vim, however there is an even better way. You don't need the loop at all:

< "$1" xargs -d\\n -n1 vim -c :q -cq

xargs will execute vim once for every line in the file given by $1.

Upvotes: 0

telenachos
telenachos

Reputation: 896

Although I'm not sure of your ultimate goal, this shell command will execute vim once per line in a.txt:

xargs -o -n1 vim -c ':q' < a.txt

As explained in the comments to Read a file line by line assigning the value to a variable, the issue you're encountering is due to the fact that vim is an interactive program and thus continues to read input from $line.

Upvotes: 0

John1024
John1024

Reputation: 113924

Replace:

vim -c ":q" -cq $line

With:

vim -c ":q" -cq "$line" </dev/tty

The redirection </dev/tty tells vim to take its standard input from the terminal. Without that, the standard input for vim is "$1".

Also, it is good practice to put $line in double-quotes to protect it from word splitting, etc.

Lastly, while vim is excellent for interactive work, if your end-goal is fully automated processing of each file, you might want to consider tools such as sed or awk.

Upvotes: 2

Related Questions