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:

for opt in $strings
do somestuff

How should I do this?


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.

  • 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. – Raphael Feb 24 '13 at 15:59
while IFS= read -r opt
done < file_with_string

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


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).


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
  • 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
  • 1
    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

My advice:

  declare -a LINES
  mapfile -t LINES
  for line in "${LINES[@]}"
  • Syntax error: bad substitution – michelemarcon Sep 19 '12 at 13:34
  • 1
    Works for me. @michelemarcon, is your bash 4.00 or never? – manatwork Sep 19 '12 at 13:36
  • GNU bash, version 2.05a.0(1)-release (arm-unknown-linux-gnu) – michelemarcon Sep 19 '12 at 13:42
  • 5
    That is ancient. Please specify this requirement in the question. – manatwork Sep 19 '12 at 13:46
  • osx 10.12.2 has ancient bash ; $ bash --version GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin16) Copyright (C) 2007 Free Software Foundation, Inc. – AnneTheAgile Dec 23 '16 at 16:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.