7

I have this bash script:

for opt in string1 string2 string3 ... string99
do somestuff

It works, but I would like to replace the explicit listing of my strings with a file which actually contains all the strings; something like this:

strings=loadFromFile
for opt in $strings
do somestuff

How should I do this?

Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
michelemarcon
  • 3,357
  • 10
  • 32
  • 37
  • 1
    See [Why is `while IFS= read` used so often, instead of `IFS=; while read..`?](http://unix.stackexchange.com/q/18886) and [In `while IFS= read..`, why does IFS have no effect?](http://unix.stackexchange.com/q/18922) – Gilles 'SO- stop being evil' Sep 20 '12 at 00:05

5 Answers5

11

while read VAR is probably best here, as it handles per-line input. You can redirect it from a file, e.g.:

while IFS= read -r THELINE; do
  echo "..$THELINE"
done </path/to/file

That'll give you each line prepended with ".."

For your example case:

while IFS= read -r opt; do
  #somestuff $opt
done </path/to/file

See Why is `while IFS= read` used so often, instead of `IFS=; while read..`? for explanations.

IBBoard
  • 298
  • 2
  • 9
  • 3
    Putting cats into pipes is bad behavior from a memory management point of view. especially when using "filter" built-in commands. @rush's answer is better, and what I use on a daily basis. – Didi Kohen Sep 19 '12 at 14:15
  • 3
    It also puts the `while` loop into a subshell, which can cause confusing behaviour if update variable values in the loop (the values will disappear when the subshell exits) – glenn jackman Sep 19 '12 at 15:48
  • If `somestuff` includes another `read`, this seems not to work properly. – Raphael Feb 23 '13 at 19:04
  • @raphael - in what way does it not "work properly"? I just tried nested reads and it works fine. – IBBoard Feb 24 '13 at 13:52
  • @IBBoard See [this new question](http://unix.stackexchange.com/questions/65955/nested-read-fails). – Raphael Feb 24 '13 at 15:59
8
while IFS= read -r opt
do 
    some_stuff
done < file_with_string

See Why is `while IFS= read` used so often, instead of `IFS=; while read..`? for explanations.

rush
  • 27,055
  • 7
  • 87
  • 112
4

The while IFS= read -r line; do ...; done < aFile is the best answer

If your strings do not contain whitespace or \[*?, you could do

for word in $(< aFile); do something; done

$(< file) is a bash feature that reads the file (like cat except without having to spawn a new process).

Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
glenn jackman
  • 84,176
  • 15
  • 116
  • 168
2

Why don't you use the readarray builtin (requires bash >= 4.0)?

readarray < FileNameFromWhereToLoad    # push every line of 
                                       # 'FileNameFromWhereToLoad' onto 
                                       # $MAPFILE by default

for i in $MAPFILE ; do
    echo $i
done
user1146332
  • 2,214
  • 13
  • 14
  • This also requires newer version of bash. – Didi Kohen Sep 19 '12 at 14:12
  • i wouldn't call `bash >= 4` new (release date was February 2009)! – user1146332 Sep 19 '12 at 14:31
  • 2
    Since he's using 2.05a, it is newer than what the asker has. In addition, some companies have avoided GPLv3 versions of bash, so do not have it in their system. – Didi Kohen Sep 19 '12 at 14:36
  • Do you have a crystal ball around? But yes, i agree with you about your last statement, i will add the version requirement of `readarray` to my answer. – user1146332 Sep 19 '12 at 14:39
  • Yes, I have a crystal ball which reflects the comment the poster wrote an hour ago on @h-dirk-schmitt answer. – Didi Kohen Sep 19 '12 at 14:45
  • 2
    I didn't read that. Thanks for the hint ;) Maybe my answer is of value for somebody who will search for an answer for a similar question!? – user1146332 Sep 19 '12 at 14:56
1

My advice:

cat INPUTFILE| {
  declare -a LINES
  mapfile -t LINES
  for line in "${LINES[@]}"
  do
    somestuff
  done
}
H.-Dirk Schmitt
  • 1,999
  • 11
  • 13