The accepted answer has subtle flaws:
- if
{{su}}
appears several times on the same line, the same replacement is performed for each pattern {{su}}
of that line,
- because
read
isn't used with IFS=
and the -r
switch, you'll get other nasty surprises: spaces are not going to be necessarily preserved, and you'll get backslash interpretations (but that's easy to fix),
- if the replacement string contains slashes or other funny characters,
sed
will be confused.
A method that works, but that involves reading the whole file in memory (it's only good for small files where you have a small number of {{su}}
):
#!/bin/bash
file=$(< filename.txt )
while [[ $file = *'{{su}}'* ]]; do
repl=$(shuf -n1 file.subjects)
file=${file/'{{su}}'/"$repl"}
done
printf '%s\n' "$file"
For an approach similar to the accepted answer, i.e., reading line by line:
#!/bin/bash
while IFS= read -r line; do
while [[ $line = *'{{su}}'* ]]; do
repl=$(shuf -n1 file.subjects)
line=${line/'{{su}}'/"$repl"}
done
printf '%s\n' "$line"
done < filename.txt
Now about the way to select a random line: while shuf
is fine, it's an external process and since it's going to be invoked many times (in a subshell), you might consider implementing something similar in Bash. If you have a limited amount of lines, you may consider slurping all the lines into an array and selecting randomly an entry from this array:
#!/bin/bash
mapfile -t replacements < file.subjects
nb_repl=${#replacements[@]}
while IFS= read -r line; do
while [[ $line = *'{{su}}'* ]]; do
repl=${replacements[RANDOM%nb_repl]}
line=${line/'{{su}}'/"$repl"}
done
printf '%s\n' "$line"
done < filename.txt
This only works if you have a “small” number of lines in file.subjects
(by small, understand less than 32767), and if you're not too worried about the distribution obtained by the modulo. There are very simple workarounds to fix this, though.
Note. You're using shuf -n1 *.subjects
. It's an error to invoke shuf
with several files (at least with my version of shuf
). So if the glob *.subjects
expands to more than one file, you'll get an error.
Note. If you don't want to run into an infinite loop, make sure that the replacements don't contain the {{su}}
pattern!