rooster
rooster

Reputation: 665

Weird behaviour with bash script

i wrote a bash script that suppose to create some files and write to them. anyway it doesnt really matter what the script does, the thing is - there is a comment in the code (at the end) which suppose only to print something to screen. and if I try to run it like that- the program doesnt write output in the files, but if put this line not as a comment (i.e remove the '##' ) then it works- the program writes the ouput to files. I reallly tried but i dont understand whats going on... If u need the rest of the script, or some more explanation about what it does just say.

files=( `ls $artists` )
echo artists=%${files[*]}%
for file in ${files[*]}; do
    echo file= $file:
    lines=`wc -l $artists/$file | cut -d" " -f1`
    echo lines=$lines
    counter=0
    while read -a line; do
        if (( $counter==$lines ));then
            break;
        fi

        if [[ ! $line =~ [^[:space:]] ]] ; then
            continue
        fi
        rank=$(( ${line[3]}+$(( 5*${line[4]} )) ))
        echo  ${line[*]}
        echo rank = $rank
        echo  "${line[*]} $rank" >> $artists/$file
        let counter++
    done < $artists/$file

    ##cat  $artists/$file | tail -$lines
    cat $artists/$file | tail -$lines > $artists/$file
done

Upvotes: 1

Views: 126

Answers (3)

jaypal singh
jaypal singh

Reputation: 77185

Redirecting to the source file will truncate the file before the next command reads it. Since you mentioned, you cannot create temporary files, how about creating named pipes.

You can re-direct and read from pipes just like they are files. Plus you can do that in parallel.

Upvotes: 0

cdarke
cdarke

Reputation: 44434

cat $artists/$file | tail -$lines > $artists/$file

Let's consider what that is doing. First you are running the cat program, which is unnecessary. It might affect the symptoms, but I doubt it.

The shell has spotted the > $artists/$file. It will TRUNCATE the file to zero bytes before running the tail program. Depending on the exact order of events, cat will be reading an empty file.

So, don't do that, try this instead:

if tail -$lines "$artists/$file" > "$artists/$file.$$"
then
    mv "$artists/$file.$$" "$artists/$file"
else
    echo "Unable to tail $artists/$file" >&2
fi

No need for cat. We redirect to a temporary filename which has the PID appended ($$). If the tail worked then we rename the temporary file to the filename required, otherwise we write an error message to stderr (fd 2). You might also consider if you want to break out of the loop or exit the program if this fails.

Defensive proramming also demands that we place any filename variables inside double quotes, in case some numpty has put whitespace inside a file or directory name (Program Files).

Upvotes: 0

Ignacio Vazquez-Abrams
Ignacio Vazquez-Abrams

Reputation: 799490

Redirecting into the source file will damage it. Redirect to a temporary file instead, and rename it after.

Upvotes: 2

Related Questions