How to pass items to bash for loop on multiple lines? - bash

I can do this in bash:
for n in a b c d e ; do
echo $n
done
If a, b, c, d, e turn out to be long lines, without using a separate variable, how do I put them each on a separate line in the for loop syntax?

Split the line with \:
$ for i in a \
> b \
> c \
> d ; do echo $i ; done
a
b
c
d

I'd use a "here document":
while read n; do
echo $n
done <<EOF
some detailed stuff here
other things on the next line, blah blah blah
EOF
Of course in this particular example you can replace the entire while loop with cat but I suppose your real code is more involved.

you can put a b c d e in a file and run a loop over that file.
while read line
do
echo "$line \n"
done < file

Related

Accessing variable value in BASH for loop

This question already has answers here:
Dynamic variable names in Bash
(19 answers)
Closed 1 hour ago.
I want to assign and print variable values within a for loop in BASH.
My code looks like this:
tea=(A B C D E F G)
c=0
for (( i=1; i<${#tea[#]}; i++ ));
do
eval "var$c=${tea[$i]}";
c=$((c+1));
echo "$var$c" >> example.txt
done
The output I get in my txt file is: 1 2 3 4 5 6. The output I expect is B C D E F G. I don't understand why am I getting this output, am I not assigning values to var$c correctly or this echo command cannot read my variable value? I would appreciate your help a lot.
One approach using a nameref:
tea=(A B C D E F G)
c=0
for (( i=1; i<${#tea[#]}; i++ ));
do
declare -n varC="var$c" # nameref
varC="${tea[$i]}"
c=$((c+1))
echo "$varC" >> example.txt
done
This generates:
$ cat example.txt
B
C
D
E
F
G

Is there a way to run same command in every input in csh?

For example:
I want to run
echo a
echo b
echo c
echo d
but with only
a
b
c
d
is it possible?

Bash: for in loop with brace expansion in list

I would like to write a for in loop in which the possible values are taken from another variable. The part that I can't figure out is how to include values that need brace expansion. For example:
TEXT="a b c d{a..c} e f"
for VAR in $TEXT; do echo $VAR; done
What i get is
a
b
c
d{a..c}
e
f
But what I want is
a
b
c
da
db
dc
e
f
Does anyone know how I can get this to work?
Thank you very much!
I fear that you may have to resort to using eval in this case...However, I'd suggest that you avoided using a loop:
eval "printf '%s\n' $TEXT"
Using eval means that the braces will be expanded, producing your desired outcome.
You can see what happens using set -x:
$ set -x
$ eval "printf '%s\n' $TEXT"
+ eval 'printf '\''%s\n'\'' a b c d{a..c} e f'
++ printf '%s\n' a b c da db dc e f
a
b
c
da
db
dc
e
f
Note that the expansion occurs before the list is passed as arguments to printf.
If you get to define $TEXT yourself and want to loop through each of its expanded elements, I'd suggest using an array instead:
text=( a b c d{a..c} e f )
for var in "${text[#]}"; do
# whatever with "$var"
done
This is the preferred solution as it doesn't involve using eval.
EDIT
While there's a time & place for eval, it's not the safest approach for the general case. See Why should eval be avoided in Bash, and what should I use instead? for some reasons why.
Use eval:
TEXT="a b c d{a..c} e f"
for VAR in $TEXT; do eval echo $VAR; done
Output:
a
b
c
da db dc
e
f
If you want to loop over every element, you'll have to nest your loops:
for VAR in $TEXT; do
for VAR2 in $(eval echo $VAR); do
echo $VAR2
done
done
Output:
a
b
c
da
db
dc
e
f
Or use the eval on TEXT rather than each element:
TEXT="$(eval echo "a b c d{a..c} e f")"
for VAR in $TEXT; do echo $VAR; done
Output:
a
b
c
da
db
dc
e
f
Without eval, but with command substitution:
$ text="$(echo a b c d{a..c} e f)"
$ echo "$text"
a b c da db dc e f
And, as mentioned in Tom's answer, an array is probably the better way to go here.

How to preserve spaces in Bash "for loop" expression

I have function that print lines with spaces and need to loop through the line with a for..in loop. How do I preserve the spaces and not tokenize based on them.
function getTwoThings
{
echo "A B C"
echo "X Y Z"
}
for L in `getTwoThings`
do
echo $L
done
for L in "`getTwoThings`"
do
echo $L
done
Produces either six things or one thing.
A
B
C
X
Y
Z
A B C X Y Z
How do I get it to produce two things?
Read it like this using process substitution:
while IFS= read -r line; do
echo "$line"
done < <(getTwoThings)
Output:
A B C
X Y Z

while loops offset in shell script

I/P file has data as follows:
Y
REQUIRES Z
A
REQUIRES B
C
REQUIRES D
REQUIRES E
REQUIRES F
G
REQUIRES H
I
REQUIRES J
EXACT OUTPUT FILE REQUIRED:
Y REQUIRES Z
A REQUIRES B
C REQUIRES D
C REQUIRES E
C REQUIRES F
G REQUIRES H
I REQUIRES J
I am using while loops to traverse the file.
while read line
do
if (condition)
{..
}
while read anoterline
do
done
done <inputfile
The problem I am facing is that
when inner while loop traverses say 4 lines and i break the inner
loop the outer while loop's offset is set to the offset at which the
inner while has stopped.
So I am missing the 4 lined data in execution of my outer loop.
I need the outer while loop to start off from the offset at which it had stopped
.
There's no reason to use nested loops here.
item=
while read -r first second _; do
if [[ $first = REQUIRES ]]; then
printf '%s REQUIRES %s\n' "$item" "$second"
else
item=$first
fi
done <inputfile
Invocation and output demonstrated at http://ideone.com/JejDyG
You can do this using awk
$ awk 'NF==1{a=$1};NF>1{print a,$0}' file
Y REQUIRES Z
A REQUIRES B
C REQUIRES D
C REQUIRES E
C REQUIRES F
G REQUIRES H
I REQUIRES J
Something like
#!/bin/bash
while read -r line; do
[[ $line =~ ^[A-Z]$ ]] && one="$line"
[[ $line =~ ^REQUIRES(.*) ]] && echo "$one $line"
done < "file"
Example
> ./abovescript
Y REQUIRES Z
A REQUIRES B
C REQUIRES D
C REQUIRES E
C REQUIRES F
G REQUIRES H
I REQUIRES J

Resources