0

I'm unable to properly handle * character in FOR loop. Bash seems to interpret it as files in current directory instead of * character.

I'm reading a file.txt that contains random words on each line. Some of the lines contain * characters and I want it being interpreted as string instead of list of files in current directory. Say file content looks like this:

cat
house
tree
****
door
book
train
aaaa
a aaa aaa
asdf

Code then reads through each line of the file, stitch new line to variable $linesToInsert together with newline character (\n) and previous content of the variable. This happens for $thisMany times, then whole built up variable is passed to insertDocument() function. This function then adds additional text around each line (stt $eachLine end) of previously built variable $linesToInsert. Issue is with for loop in this function. I can't make bash not interpret it as string of ***** characters, instead it lists files in current directory.

thisMany=5


insertDocument() {
        documentToInsert=
        IFS=$'\n'
        for eachLine in $1; do
                documentToInsert="$documentToInsert"'{ '"$eachLine"' } '
        done
        echo "$documentToInsert"
}

linesToInsert=

while read i
do
        linesToInsert="${linesToInsert}"$'\n'"${i}";
        cntr=$((cntr+1))

        if [ $cntr -eq $thisMany ]; then

                insertDocument "$linesToInsert"
                cntr=0
                linesToInsert=
        fi
done <file.txt

insertDocument "$linesToInsert"

Output should be something like this:

{ cat } { house } { tree } { **** } { door } { book } { train } { aaaa } { a aaa aaa } { asdf }

But I'm getting something like this:

{ cat } { house } { tree } { file1.txt } { file2.txt } { file3.txt } { file4.txt } { file1.txt } { door } { book } { train } { aaaa } { a aaa aaa } { asdf }

Could you please help me make bash properly escape * character in FOR loop?

  • 2
    The general way to handle this is to not try to read lines with `for` (use a `while read` loop instead).In this case it seems like your whole current script could be `sed -e 's/.*/{ & } /g' file.txt | tr -d '\n'` though, and there are several other better solutions in between. I'm not sure what exactly you want to keep for your actual problem. In particular, if this is supposed to generate JSON you should definitely not go in this direction at all – that other guy Jan 18 '19 at 00:37
  • 1
    Don't ever run `for eachLine in $i`; see [DontReadLinesWithFor](https://mywiki.wooledge.org/DontReadLinesWithFor). And audit all your escapes -- http://shellcheck.net/ will warn on unquoted expansions. – Charles Duffy Jan 18 '19 at 01:09
  • [BashFAQ #1](http://mywiki.wooledge.org/BashFAQ/001) describes best practices for consuming a file line-by-line in bash. – Charles Duffy Jan 18 '19 at 01:12
  • [reading asterisk character from a file in bash](https://stackoverflow.com/questions/53751907/reading-asterisk-character-from-a-file-in-bash) is related, but the OP there is *starting* with a better-practice approach (but getting an expansion later), so it's not quite an exact duplicate. – Charles Duffy Jan 18 '19 at 01:13

1 Answers1

0

To prevent the asterix expansion, you can add this line, just before calling insertDocument:

set -f

That is:

set -f
insertDocument "$linesToInsert"
Yoric
  • 1,761
  • 2
  • 13
  • 15
  • 1
    It works, but it's hardly a best-practice fix -- you're making a behavior change that needs to either be reversed or will modify all code that runs later in the same shell. – Charles Duffy Jan 18 '19 at 01:10