jeannej
jeannej

Reputation: 1216

Bash while read loop messes variables definition

I have a csv file test_list containing only lines of text:

> cat $test_list
test_name_1
test_name_2
> typeset -p test_list
declare -- test_list="test_list.csv"

I want to test that each test_name related files exist and return a message if not. In a MINGW64 shell, doing:

while read -r test_name || [ -n "$line" ]; do 
    echo $test_name
    if [ ! -f "./$test_name/$test_name.txt" ]; then
        echo "$(pwd)/$test_name/$test_name.txt not found! Check for any typo in the file name."
    fi  
done < $test_list

Returns (same if I protect with ${test_name}):

test_name_1
.txt not found! Check for any typo in the file name._name_1
test_name_2
.txt not found! Check for any typo in the file name._name_2

So echo $test_name returns what I would expect. But why does echo "$(pwd)/$test_name/$test_name.txt not found!" (nor echo $(pwd)/$test_name/$test_name".txt not found!) not interpret the path correctly?

Plus, the file are indeed present, so the condition should not be met in the first place, so the path is not correctly interpreted in if [ ! -f "./$test_name/$test_name.txt" ] neither.

When I test the inside of the while loop in the shell by declaring test_name="test_name_1", the echo works fine, as does the condition. So I guess the problem is in how $test_name is interpreted in the while read loop, but I do not know how to debug it further. Do you have an idea?

PS: I struggled to define the title of this question so feel free to change it for a more appropriate one


Fixes

I had trouble knowing what to search for to solve my problem, so in case someone else ends up here, there are the fixes.

I had \r (not visible in Notepad++) in my csv file that prevented the -f test to work properly. This is also what caused the output wrapping back on itself (with the _name_1 at the end). The existance of these \r can be checked with:

od -c "$test_list"

and fixed by adding before the while loop:

dos2unix $test_list

Aside from that, the variable names should be the same in while read -r x || [ -n "$x" ] (prevents failing to read a last line not terminated by a newline). This is the working code:

dos2unix $test_list
while read -r line || [ -n "$line" ]; do 
    echo $line
    if [ ! -f "./$line/$line.tst" ]; then
        echo "$(pwd)/$line/$line.tst not found! Check for any typo in the file name."
    fi  
done < $test_list

Many thanks to @markp-fuso and @pmf for their help!

Upvotes: 1

Views: 50

Answers (1)

Diego Torres Milano
Diego Torres Milano

Reputation: 69358

You can use xargs instead of the loop

xargs -I '{}' bash -c "test -f '{}' || echo '$(pwd)/{} not found! Check for any typo in the file name.'" < test_list

Upvotes: 1

Related Questions