Iterate through multiline string line by line The 2019 Stack Overflow Developer Survey Results Are In Announcing the arrival of Valued Associate #679: Cesar Manara Planned maintenance scheduled April 17/18, 2019 at 00:00UTC (8:00pm US/Eastern) 2019 Community Moderator Election Results Why I closed the “Why is Kali so hard” questionWhy is printf better than echo?Why is using a shell loop to process text considered bad practice?Are there naming conventions for variables in shell scripts?Why is my variable local in one 'while read' loop, but not in another seemingly similar loop?Understanding IFSWhat should interactive shells do in orphaned process groups?for loop to iterate through some file nth positionCron only occasionally sends e-mail on output and errorsIterate Through Sets of Command Arguments in Bashhow to iterate through files in directory excluding hidden filesStarting an interactive shell as an asynchronous process (signal delivery)Control characters in a terminal with an active foreground processhow to let sudo fork bash instead of sh?Multiline command : comment out one line
How do you keep chess fun when your opponent constantly beats you?
Didn't get enough time to take a Coding Test - what to do now?
First use of “packing” as in carrying a gun
When did F become S in typeography, and why?
Am I ethically obligated to go into work on an off day if the reason is sudden?
How did passengers keep warm on sail ships?
Why can't wing-mounted spoilers be used to steepen approaches?
Are spiders unable to hurt humans, especially very small spiders?
Finding the path in a graph from A to B then back to A with a minimum of shared edges
Can withdrawing asylum be illegal?
Windows 10: How to Lock (not sleep) laptop on lid close?
What can I do if neighbor is blocking my solar panels intentionally?
Semisimplicity of the category of coherent sheaves?
Is every episode of "Where are my Pants?" identical?
How did the audience guess the pentatonic scale in Bobby McFerrin's presentation?
Segmentation fault output is suppressed when piping stdin into a function. Why?
Hopping to infinity along a string of digits
Is there a writing software that you can sort scenes like slides in PowerPoint?
Relations between two reciprocal partial derivatives?
He got a vote 80% that of Emmanuel Macron’s
Are my PIs rude or am I just being too sensitive?
Make it rain characters
Do working physicists consider Newtonian mechanics to be "falsified"?
Is a pteranodon too powerful as a beast companion for a beast master?
Iterate through multiline string line by line
The 2019 Stack Overflow Developer Survey Results Are In
Announcing the arrival of Valued Associate #679: Cesar Manara
Planned maintenance scheduled April 17/18, 2019 at 00:00UTC (8:00pm US/Eastern)
2019 Community Moderator Election Results
Why I closed the “Why is Kali so hard” questionWhy is printf better than echo?Why is using a shell loop to process text considered bad practice?Are there naming conventions for variables in shell scripts?Why is my variable local in one 'while read' loop, but not in another seemingly similar loop?Understanding IFSWhat should interactive shells do in orphaned process groups?for loop to iterate through some file nth positionCron only occasionally sends e-mail on output and errorsIterate Through Sets of Command Arguments in Bashhow to iterate through files in directory excluding hidden filesStarting an interactive shell as an asynchronous process (signal delivery)Control characters in a terminal with an active foreground processhow to let sudo fork bash instead of sh?Multiline command : comment out one line
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;
I would like to process a multiline string and iterate it line by line, in a POSIX shell (/bin/sh
) on a BSD platform. Bash is not included in the base BSD-distribution and has a GPL license - so I am trying to make it universally work with /bin/sh
instead.
I found a solution using a pipe, however in the regular /bin/sh
shell, these a processed in a separate process, meaning the following does not work:
MULTILINE="`cat $SOMEFILE`"
SOMEVAR="original value"
echo "$MULTILINE" | while IFS= read -r SINGLELINE
do
SOMEVAR="updated value"
echo "this is a single line: $SINGLELINE"
echo "SOMEVAR is now: $SOMEVAR"
done
echo "Final SOMEVAR is unchanged: $SOMEVAR"
In the above example, it accomplishes what I want, except for the fact that changes to variables such as $SOMEVAR
are not accessible outside the while loop.
My question: how can I accomplish something like the above without this restriction? Note that many solutions require Bash, whereas I am using the standard POSIX-shell /bin/sh
.
shell
add a comment |
I would like to process a multiline string and iterate it line by line, in a POSIX shell (/bin/sh
) on a BSD platform. Bash is not included in the base BSD-distribution and has a GPL license - so I am trying to make it universally work with /bin/sh
instead.
I found a solution using a pipe, however in the regular /bin/sh
shell, these a processed in a separate process, meaning the following does not work:
MULTILINE="`cat $SOMEFILE`"
SOMEVAR="original value"
echo "$MULTILINE" | while IFS= read -r SINGLELINE
do
SOMEVAR="updated value"
echo "this is a single line: $SINGLELINE"
echo "SOMEVAR is now: $SOMEVAR"
done
echo "Final SOMEVAR is unchanged: $SOMEVAR"
In the above example, it accomplishes what I want, except for the fact that changes to variables such as $SOMEVAR
are not accessible outside the while loop.
My question: how can I accomplish something like the above without this restriction? Note that many solutions require Bash, whereas I am using the standard POSIX-shell /bin/sh
.
shell
Why can you not usebash
? (add to your question)
– ctrl-alt-delor
Mar 31 at 10:54
I can not reproduce your issue using/bin/sh
on a BSD system. There is nothing in this code that would requirebash
.
– Kusalananda♦
Mar 31 at 10:57
My apologies. In trying to create a minimized sample of the actual issue, i made some errors. I updated the code sample now, and it should reflect the problem correctly now. The example indeed does not require Bash.
– Steiner
Mar 31 at 11:09
@Steiner In fact, it would have the same issue inbash
.
– Kusalananda♦
Mar 31 at 11:21
3
There is no Bourne shell on the BSDs. Nor is the Bourne shell standard. Do not conflate the Bourne shell with a POSIX-conformantsh
.
– JdeBP
Mar 31 at 11:29
add a comment |
I would like to process a multiline string and iterate it line by line, in a POSIX shell (/bin/sh
) on a BSD platform. Bash is not included in the base BSD-distribution and has a GPL license - so I am trying to make it universally work with /bin/sh
instead.
I found a solution using a pipe, however in the regular /bin/sh
shell, these a processed in a separate process, meaning the following does not work:
MULTILINE="`cat $SOMEFILE`"
SOMEVAR="original value"
echo "$MULTILINE" | while IFS= read -r SINGLELINE
do
SOMEVAR="updated value"
echo "this is a single line: $SINGLELINE"
echo "SOMEVAR is now: $SOMEVAR"
done
echo "Final SOMEVAR is unchanged: $SOMEVAR"
In the above example, it accomplishes what I want, except for the fact that changes to variables such as $SOMEVAR
are not accessible outside the while loop.
My question: how can I accomplish something like the above without this restriction? Note that many solutions require Bash, whereas I am using the standard POSIX-shell /bin/sh
.
shell
I would like to process a multiline string and iterate it line by line, in a POSIX shell (/bin/sh
) on a BSD platform. Bash is not included in the base BSD-distribution and has a GPL license - so I am trying to make it universally work with /bin/sh
instead.
I found a solution using a pipe, however in the regular /bin/sh
shell, these a processed in a separate process, meaning the following does not work:
MULTILINE="`cat $SOMEFILE`"
SOMEVAR="original value"
echo "$MULTILINE" | while IFS= read -r SINGLELINE
do
SOMEVAR="updated value"
echo "this is a single line: $SINGLELINE"
echo "SOMEVAR is now: $SOMEVAR"
done
echo "Final SOMEVAR is unchanged: $SOMEVAR"
In the above example, it accomplishes what I want, except for the fact that changes to variables such as $SOMEVAR
are not accessible outside the while loop.
My question: how can I accomplish something like the above without this restriction? Note that many solutions require Bash, whereas I am using the standard POSIX-shell /bin/sh
.
shell
shell
edited Mar 31 at 11:44
Steiner
asked Mar 31 at 10:52
SteinerSteiner
908
908
Why can you not usebash
? (add to your question)
– ctrl-alt-delor
Mar 31 at 10:54
I can not reproduce your issue using/bin/sh
on a BSD system. There is nothing in this code that would requirebash
.
– Kusalananda♦
Mar 31 at 10:57
My apologies. In trying to create a minimized sample of the actual issue, i made some errors. I updated the code sample now, and it should reflect the problem correctly now. The example indeed does not require Bash.
– Steiner
Mar 31 at 11:09
@Steiner In fact, it would have the same issue inbash
.
– Kusalananda♦
Mar 31 at 11:21
3
There is no Bourne shell on the BSDs. Nor is the Bourne shell standard. Do not conflate the Bourne shell with a POSIX-conformantsh
.
– JdeBP
Mar 31 at 11:29
add a comment |
Why can you not usebash
? (add to your question)
– ctrl-alt-delor
Mar 31 at 10:54
I can not reproduce your issue using/bin/sh
on a BSD system. There is nothing in this code that would requirebash
.
– Kusalananda♦
Mar 31 at 10:57
My apologies. In trying to create a minimized sample of the actual issue, i made some errors. I updated the code sample now, and it should reflect the problem correctly now. The example indeed does not require Bash.
– Steiner
Mar 31 at 11:09
@Steiner In fact, it would have the same issue inbash
.
– Kusalananda♦
Mar 31 at 11:21
3
There is no Bourne shell on the BSDs. Nor is the Bourne shell standard. Do not conflate the Bourne shell with a POSIX-conformantsh
.
– JdeBP
Mar 31 at 11:29
Why can you not use
bash
? (add to your question)– ctrl-alt-delor
Mar 31 at 10:54
Why can you not use
bash
? (add to your question)– ctrl-alt-delor
Mar 31 at 10:54
I can not reproduce your issue using
/bin/sh
on a BSD system. There is nothing in this code that would require bash
.– Kusalananda♦
Mar 31 at 10:57
I can not reproduce your issue using
/bin/sh
on a BSD system. There is nothing in this code that would require bash
.– Kusalananda♦
Mar 31 at 10:57
My apologies. In trying to create a minimized sample of the actual issue, i made some errors. I updated the code sample now, and it should reflect the problem correctly now. The example indeed does not require Bash.
– Steiner
Mar 31 at 11:09
My apologies. In trying to create a minimized sample of the actual issue, i made some errors. I updated the code sample now, and it should reflect the problem correctly now. The example indeed does not require Bash.
– Steiner
Mar 31 at 11:09
@Steiner In fact, it would have the same issue in
bash
.– Kusalananda♦
Mar 31 at 11:21
@Steiner In fact, it would have the same issue in
bash
.– Kusalananda♦
Mar 31 at 11:21
3
3
There is no Bourne shell on the BSDs. Nor is the Bourne shell standard. Do not conflate the Bourne shell with a POSIX-conformant
sh
.– JdeBP
Mar 31 at 11:29
There is no Bourne shell on the BSDs. Nor is the Bourne shell standard. Do not conflate the Bourne shell with a POSIX-conformant
sh
.– JdeBP
Mar 31 at 11:29
add a comment |
3 Answers
3
active
oldest
votes
You could use a here document:
while IFS= read -r SINGLELINE
do
SOMEVAR="updated value"
printf '%sn' "this is a single line: $SINGLELINE"
printf '%sn' "SOMEVAR is now: $SOMEVAR"
done << EOF
$MULTILINE
EOF
printf '%sn' "Final SOMEVAL is still $SOMEVAR"
Depending on the sh
implementation, here-documents are implemented either as a deleted temporary file where the shell has stored the expansion of the variable followed by newline beforehand, or a pipe to which the shell feeds the expansion of the variable followed by newline. But in either case, except in the original Bourne shell (a shell that is no longer in use these days and is not a POSIX compliant shell), the command being redirected is not run in a subshell (as POSIX requires).
or you could use split+glob:
IFS='
' # split on newline only
set -o noglob
for SINGLELINE in $MULTILINE
do
SOMEVAR="updated value"
printf '%sn' "this is a single line: $SINGLELINE"
printf '%sn' "SOMEVAR is now: $SOMEVAR"
done
printf '%sn' "Final SOMEVAL is still $SOMEVAR"
But beware it skips empty lines.
Both solutions worked well for me with/bin/sh
. I think this solution is better than the one Kusalananda provided, though his answer is very informative too. I particularly like the for-loop solution since it probably is faster because it does not useread
which is very slow. Thanks!
– Steiner
Mar 31 at 15:54
@Steiner (Just had to quickly double check so that I didn't have afor
-loop solution, which I fortunately did not have)
– Kusalananda♦
Mar 31 at 18:41
add a comment |
You would read directly from the file without the pipeline. This avoids running the while
loop in a subshell, which allows you to see the changed value of $SOMEVALUE
after the loop.
SOMEVAR="original value"
while IFS= read -r SINGLELINE
do
SOMEVAR="updated value"
printf 'this is a single line: %sn' "$SINGLELINE"
printf 'SOMEVAR is now: %sn' "$SOMEVAR"
done <"$SOMEFILE"
printf 'Final SOMEVAR is: %sn' "$SOMEVAR"
If you insist on having your $MULTILINE
variable, then write that to a file and read it from there:
tmpfile=$(mktemp)
printf '%sn' "$MULTILINE" >"$tmpfile"
while ...; do
...
done <"$tmpfile"
rm "$tmpfile"
Also related:
- Why is my variable local in one 'while read' loop, but not in another seemingly similar loop?
An answer to the above linked question also suggests writing your program in such a way that all uses of $SOMEVAR
occurs within the subshell at the end of the pipeline:
MULTILINE=$(cat "$SOMEFILE")
SOMEVAR="original value"
printf '%sn' "$MULTILINE" |
while IFS= read -r SINGLELINE
do
SOMEVAR="updated value"
printf 'this is a single line: %sn' "$SINGLELINE"
printf 'SOMEVAR is now: %sn' "$SOMEVAR"
done
printf 'Final SOMEVAR is: %sn' "$SOMEVAR"
Also possibly related:
- Why is using a shell loop to process text considered bad practice?
Other questions that may be of interest:
- Why is printf better than echo?
- Are there naming conventions for variables in shell scripts?
Indeed this works, but requires a file to be fed to the while-loop. My actual code is more complex, and requires a modified multiline string to be fed to the while-loop. Your solution to write this multiline string to a temporary file works, but is there a solution that does not require writing a temporary file?
– Steiner
Mar 31 at 11:28
@Steiner See update answer. There's not much else you could do without using features of specific shells.
– Kusalananda♦
Mar 31 at 11:33
Thank you that answers my question. The suggestion at the end and the links provided are very helpful too!
– Steiner
Mar 31 at 11:43
@Steiner ... except for using a here-document. Well, there's a thing I didn't think of :-)
– Kusalananda♦
Mar 31 at 18:42
add a comment |
It works for me :
$ cat bin/test
#! /bin/sh
SOMEFILE=$1
MULTILINE="`cat $SOMEFILE`"
SOMEVAR="blah"
echo "$MULTILINE" | while IFS= read -r SINGLELINE
do
echo "this is a single line: $SINGLELINE"
echo "but accessing this var fails: $SOMEVAR"
done
and
$ bin/test bin/test
this is a single line: #! /bin/sh
but accessing this var fails: blah
this is a single line: SOMEFILE=$1
but accessing this var fails: blah
this is a single line: MULTILINE="`cat $SOMEFILE`"
but accessing this var fails: blah
this is a single line: SOMEVAR="blah"
but accessing this var fails: blah
this is a single line:
but accessing this var fails: blah
this is a single line: echo "$MULTILINE" | while IFS= read -r SINGLELINE
but accessing this var fails: blah
this is a single line: do
but accessing this var fails: blah
this is a single line: echo "this is a single line: $SINGLELINE"
but accessing this var fails: blah
this is a single line: echo "but accessing this var fails: $SOMEVAR"
but accessing this var fails: blah
this is a single line: done
but accessing this var fails: blah
My apologies. In trying to create a minimized sample of the actual issue, i made some errors. I updated the code sample now, and it should reflect the problem correctly now.
– Steiner
Mar 31 at 11:13
add a comment |
Your Answer
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "106"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f509714%2fiterate-through-multiline-string-line-by-line%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
You could use a here document:
while IFS= read -r SINGLELINE
do
SOMEVAR="updated value"
printf '%sn' "this is a single line: $SINGLELINE"
printf '%sn' "SOMEVAR is now: $SOMEVAR"
done << EOF
$MULTILINE
EOF
printf '%sn' "Final SOMEVAL is still $SOMEVAR"
Depending on the sh
implementation, here-documents are implemented either as a deleted temporary file where the shell has stored the expansion of the variable followed by newline beforehand, or a pipe to which the shell feeds the expansion of the variable followed by newline. But in either case, except in the original Bourne shell (a shell that is no longer in use these days and is not a POSIX compliant shell), the command being redirected is not run in a subshell (as POSIX requires).
or you could use split+glob:
IFS='
' # split on newline only
set -o noglob
for SINGLELINE in $MULTILINE
do
SOMEVAR="updated value"
printf '%sn' "this is a single line: $SINGLELINE"
printf '%sn' "SOMEVAR is now: $SOMEVAR"
done
printf '%sn' "Final SOMEVAL is still $SOMEVAR"
But beware it skips empty lines.
Both solutions worked well for me with/bin/sh
. I think this solution is better than the one Kusalananda provided, though his answer is very informative too. I particularly like the for-loop solution since it probably is faster because it does not useread
which is very slow. Thanks!
– Steiner
Mar 31 at 15:54
@Steiner (Just had to quickly double check so that I didn't have afor
-loop solution, which I fortunately did not have)
– Kusalananda♦
Mar 31 at 18:41
add a comment |
You could use a here document:
while IFS= read -r SINGLELINE
do
SOMEVAR="updated value"
printf '%sn' "this is a single line: $SINGLELINE"
printf '%sn' "SOMEVAR is now: $SOMEVAR"
done << EOF
$MULTILINE
EOF
printf '%sn' "Final SOMEVAL is still $SOMEVAR"
Depending on the sh
implementation, here-documents are implemented either as a deleted temporary file where the shell has stored the expansion of the variable followed by newline beforehand, or a pipe to which the shell feeds the expansion of the variable followed by newline. But in either case, except in the original Bourne shell (a shell that is no longer in use these days and is not a POSIX compliant shell), the command being redirected is not run in a subshell (as POSIX requires).
or you could use split+glob:
IFS='
' # split on newline only
set -o noglob
for SINGLELINE in $MULTILINE
do
SOMEVAR="updated value"
printf '%sn' "this is a single line: $SINGLELINE"
printf '%sn' "SOMEVAR is now: $SOMEVAR"
done
printf '%sn' "Final SOMEVAL is still $SOMEVAR"
But beware it skips empty lines.
Both solutions worked well for me with/bin/sh
. I think this solution is better than the one Kusalananda provided, though his answer is very informative too. I particularly like the for-loop solution since it probably is faster because it does not useread
which is very slow. Thanks!
– Steiner
Mar 31 at 15:54
@Steiner (Just had to quickly double check so that I didn't have afor
-loop solution, which I fortunately did not have)
– Kusalananda♦
Mar 31 at 18:41
add a comment |
You could use a here document:
while IFS= read -r SINGLELINE
do
SOMEVAR="updated value"
printf '%sn' "this is a single line: $SINGLELINE"
printf '%sn' "SOMEVAR is now: $SOMEVAR"
done << EOF
$MULTILINE
EOF
printf '%sn' "Final SOMEVAL is still $SOMEVAR"
Depending on the sh
implementation, here-documents are implemented either as a deleted temporary file where the shell has stored the expansion of the variable followed by newline beforehand, or a pipe to which the shell feeds the expansion of the variable followed by newline. But in either case, except in the original Bourne shell (a shell that is no longer in use these days and is not a POSIX compliant shell), the command being redirected is not run in a subshell (as POSIX requires).
or you could use split+glob:
IFS='
' # split on newline only
set -o noglob
for SINGLELINE in $MULTILINE
do
SOMEVAR="updated value"
printf '%sn' "this is a single line: $SINGLELINE"
printf '%sn' "SOMEVAR is now: $SOMEVAR"
done
printf '%sn' "Final SOMEVAL is still $SOMEVAR"
But beware it skips empty lines.
You could use a here document:
while IFS= read -r SINGLELINE
do
SOMEVAR="updated value"
printf '%sn' "this is a single line: $SINGLELINE"
printf '%sn' "SOMEVAR is now: $SOMEVAR"
done << EOF
$MULTILINE
EOF
printf '%sn' "Final SOMEVAL is still $SOMEVAR"
Depending on the sh
implementation, here-documents are implemented either as a deleted temporary file where the shell has stored the expansion of the variable followed by newline beforehand, or a pipe to which the shell feeds the expansion of the variable followed by newline. But in either case, except in the original Bourne shell (a shell that is no longer in use these days and is not a POSIX compliant shell), the command being redirected is not run in a subshell (as POSIX requires).
or you could use split+glob:
IFS='
' # split on newline only
set -o noglob
for SINGLELINE in $MULTILINE
do
SOMEVAR="updated value"
printf '%sn' "this is a single line: $SINGLELINE"
printf '%sn' "SOMEVAR is now: $SOMEVAR"
done
printf '%sn' "Final SOMEVAL is still $SOMEVAR"
But beware it skips empty lines.
edited Mar 31 at 18:03
answered Mar 31 at 13:42
Stéphane ChazelasStéphane Chazelas
314k57594952
314k57594952
Both solutions worked well for me with/bin/sh
. I think this solution is better than the one Kusalananda provided, though his answer is very informative too. I particularly like the for-loop solution since it probably is faster because it does not useread
which is very slow. Thanks!
– Steiner
Mar 31 at 15:54
@Steiner (Just had to quickly double check so that I didn't have afor
-loop solution, which I fortunately did not have)
– Kusalananda♦
Mar 31 at 18:41
add a comment |
Both solutions worked well for me with/bin/sh
. I think this solution is better than the one Kusalananda provided, though his answer is very informative too. I particularly like the for-loop solution since it probably is faster because it does not useread
which is very slow. Thanks!
– Steiner
Mar 31 at 15:54
@Steiner (Just had to quickly double check so that I didn't have afor
-loop solution, which I fortunately did not have)
– Kusalananda♦
Mar 31 at 18:41
Both solutions worked well for me with
/bin/sh
. I think this solution is better than the one Kusalananda provided, though his answer is very informative too. I particularly like the for-loop solution since it probably is faster because it does not use read
which is very slow. Thanks!– Steiner
Mar 31 at 15:54
Both solutions worked well for me with
/bin/sh
. I think this solution is better than the one Kusalananda provided, though his answer is very informative too. I particularly like the for-loop solution since it probably is faster because it does not use read
which is very slow. Thanks!– Steiner
Mar 31 at 15:54
@Steiner (Just had to quickly double check so that I didn't have a
for
-loop solution, which I fortunately did not have)– Kusalananda♦
Mar 31 at 18:41
@Steiner (Just had to quickly double check so that I didn't have a
for
-loop solution, which I fortunately did not have)– Kusalananda♦
Mar 31 at 18:41
add a comment |
You would read directly from the file without the pipeline. This avoids running the while
loop in a subshell, which allows you to see the changed value of $SOMEVALUE
after the loop.
SOMEVAR="original value"
while IFS= read -r SINGLELINE
do
SOMEVAR="updated value"
printf 'this is a single line: %sn' "$SINGLELINE"
printf 'SOMEVAR is now: %sn' "$SOMEVAR"
done <"$SOMEFILE"
printf 'Final SOMEVAR is: %sn' "$SOMEVAR"
If you insist on having your $MULTILINE
variable, then write that to a file and read it from there:
tmpfile=$(mktemp)
printf '%sn' "$MULTILINE" >"$tmpfile"
while ...; do
...
done <"$tmpfile"
rm "$tmpfile"
Also related:
- Why is my variable local in one 'while read' loop, but not in another seemingly similar loop?
An answer to the above linked question also suggests writing your program in such a way that all uses of $SOMEVAR
occurs within the subshell at the end of the pipeline:
MULTILINE=$(cat "$SOMEFILE")
SOMEVAR="original value"
printf '%sn' "$MULTILINE" |
while IFS= read -r SINGLELINE
do
SOMEVAR="updated value"
printf 'this is a single line: %sn' "$SINGLELINE"
printf 'SOMEVAR is now: %sn' "$SOMEVAR"
done
printf 'Final SOMEVAR is: %sn' "$SOMEVAR"
Also possibly related:
- Why is using a shell loop to process text considered bad practice?
Other questions that may be of interest:
- Why is printf better than echo?
- Are there naming conventions for variables in shell scripts?
Indeed this works, but requires a file to be fed to the while-loop. My actual code is more complex, and requires a modified multiline string to be fed to the while-loop. Your solution to write this multiline string to a temporary file works, but is there a solution that does not require writing a temporary file?
– Steiner
Mar 31 at 11:28
@Steiner See update answer. There's not much else you could do without using features of specific shells.
– Kusalananda♦
Mar 31 at 11:33
Thank you that answers my question. The suggestion at the end and the links provided are very helpful too!
– Steiner
Mar 31 at 11:43
@Steiner ... except for using a here-document. Well, there's a thing I didn't think of :-)
– Kusalananda♦
Mar 31 at 18:42
add a comment |
You would read directly from the file without the pipeline. This avoids running the while
loop in a subshell, which allows you to see the changed value of $SOMEVALUE
after the loop.
SOMEVAR="original value"
while IFS= read -r SINGLELINE
do
SOMEVAR="updated value"
printf 'this is a single line: %sn' "$SINGLELINE"
printf 'SOMEVAR is now: %sn' "$SOMEVAR"
done <"$SOMEFILE"
printf 'Final SOMEVAR is: %sn' "$SOMEVAR"
If you insist on having your $MULTILINE
variable, then write that to a file and read it from there:
tmpfile=$(mktemp)
printf '%sn' "$MULTILINE" >"$tmpfile"
while ...; do
...
done <"$tmpfile"
rm "$tmpfile"
Also related:
- Why is my variable local in one 'while read' loop, but not in another seemingly similar loop?
An answer to the above linked question also suggests writing your program in such a way that all uses of $SOMEVAR
occurs within the subshell at the end of the pipeline:
MULTILINE=$(cat "$SOMEFILE")
SOMEVAR="original value"
printf '%sn' "$MULTILINE" |
while IFS= read -r SINGLELINE
do
SOMEVAR="updated value"
printf 'this is a single line: %sn' "$SINGLELINE"
printf 'SOMEVAR is now: %sn' "$SOMEVAR"
done
printf 'Final SOMEVAR is: %sn' "$SOMEVAR"
Also possibly related:
- Why is using a shell loop to process text considered bad practice?
Other questions that may be of interest:
- Why is printf better than echo?
- Are there naming conventions for variables in shell scripts?
Indeed this works, but requires a file to be fed to the while-loop. My actual code is more complex, and requires a modified multiline string to be fed to the while-loop. Your solution to write this multiline string to a temporary file works, but is there a solution that does not require writing a temporary file?
– Steiner
Mar 31 at 11:28
@Steiner See update answer. There's not much else you could do without using features of specific shells.
– Kusalananda♦
Mar 31 at 11:33
Thank you that answers my question. The suggestion at the end and the links provided are very helpful too!
– Steiner
Mar 31 at 11:43
@Steiner ... except for using a here-document. Well, there's a thing I didn't think of :-)
– Kusalananda♦
Mar 31 at 18:42
add a comment |
You would read directly from the file without the pipeline. This avoids running the while
loop in a subshell, which allows you to see the changed value of $SOMEVALUE
after the loop.
SOMEVAR="original value"
while IFS= read -r SINGLELINE
do
SOMEVAR="updated value"
printf 'this is a single line: %sn' "$SINGLELINE"
printf 'SOMEVAR is now: %sn' "$SOMEVAR"
done <"$SOMEFILE"
printf 'Final SOMEVAR is: %sn' "$SOMEVAR"
If you insist on having your $MULTILINE
variable, then write that to a file and read it from there:
tmpfile=$(mktemp)
printf '%sn' "$MULTILINE" >"$tmpfile"
while ...; do
...
done <"$tmpfile"
rm "$tmpfile"
Also related:
- Why is my variable local in one 'while read' loop, but not in another seemingly similar loop?
An answer to the above linked question also suggests writing your program in such a way that all uses of $SOMEVAR
occurs within the subshell at the end of the pipeline:
MULTILINE=$(cat "$SOMEFILE")
SOMEVAR="original value"
printf '%sn' "$MULTILINE" |
while IFS= read -r SINGLELINE
do
SOMEVAR="updated value"
printf 'this is a single line: %sn' "$SINGLELINE"
printf 'SOMEVAR is now: %sn' "$SOMEVAR"
done
printf 'Final SOMEVAR is: %sn' "$SOMEVAR"
Also possibly related:
- Why is using a shell loop to process text considered bad practice?
Other questions that may be of interest:
- Why is printf better than echo?
- Are there naming conventions for variables in shell scripts?
You would read directly from the file without the pipeline. This avoids running the while
loop in a subshell, which allows you to see the changed value of $SOMEVALUE
after the loop.
SOMEVAR="original value"
while IFS= read -r SINGLELINE
do
SOMEVAR="updated value"
printf 'this is a single line: %sn' "$SINGLELINE"
printf 'SOMEVAR is now: %sn' "$SOMEVAR"
done <"$SOMEFILE"
printf 'Final SOMEVAR is: %sn' "$SOMEVAR"
If you insist on having your $MULTILINE
variable, then write that to a file and read it from there:
tmpfile=$(mktemp)
printf '%sn' "$MULTILINE" >"$tmpfile"
while ...; do
...
done <"$tmpfile"
rm "$tmpfile"
Also related:
- Why is my variable local in one 'while read' loop, but not in another seemingly similar loop?
An answer to the above linked question also suggests writing your program in such a way that all uses of $SOMEVAR
occurs within the subshell at the end of the pipeline:
MULTILINE=$(cat "$SOMEFILE")
SOMEVAR="original value"
printf '%sn' "$MULTILINE" |
while IFS= read -r SINGLELINE
do
SOMEVAR="updated value"
printf 'this is a single line: %sn' "$SINGLELINE"
printf 'SOMEVAR is now: %sn' "$SOMEVAR"
done
printf 'Final SOMEVAR is: %sn' "$SOMEVAR"
Also possibly related:
- Why is using a shell loop to process text considered bad practice?
Other questions that may be of interest:
- Why is printf better than echo?
- Are there naming conventions for variables in shell scripts?
edited Mar 31 at 11:35
answered Mar 31 at 11:24
Kusalananda♦Kusalananda
141k18263439
141k18263439
Indeed this works, but requires a file to be fed to the while-loop. My actual code is more complex, and requires a modified multiline string to be fed to the while-loop. Your solution to write this multiline string to a temporary file works, but is there a solution that does not require writing a temporary file?
– Steiner
Mar 31 at 11:28
@Steiner See update answer. There's not much else you could do without using features of specific shells.
– Kusalananda♦
Mar 31 at 11:33
Thank you that answers my question. The suggestion at the end and the links provided are very helpful too!
– Steiner
Mar 31 at 11:43
@Steiner ... except for using a here-document. Well, there's a thing I didn't think of :-)
– Kusalananda♦
Mar 31 at 18:42
add a comment |
Indeed this works, but requires a file to be fed to the while-loop. My actual code is more complex, and requires a modified multiline string to be fed to the while-loop. Your solution to write this multiline string to a temporary file works, but is there a solution that does not require writing a temporary file?
– Steiner
Mar 31 at 11:28
@Steiner See update answer. There's not much else you could do without using features of specific shells.
– Kusalananda♦
Mar 31 at 11:33
Thank you that answers my question. The suggestion at the end and the links provided are very helpful too!
– Steiner
Mar 31 at 11:43
@Steiner ... except for using a here-document. Well, there's a thing I didn't think of :-)
– Kusalananda♦
Mar 31 at 18:42
Indeed this works, but requires a file to be fed to the while-loop. My actual code is more complex, and requires a modified multiline string to be fed to the while-loop. Your solution to write this multiline string to a temporary file works, but is there a solution that does not require writing a temporary file?
– Steiner
Mar 31 at 11:28
Indeed this works, but requires a file to be fed to the while-loop. My actual code is more complex, and requires a modified multiline string to be fed to the while-loop. Your solution to write this multiline string to a temporary file works, but is there a solution that does not require writing a temporary file?
– Steiner
Mar 31 at 11:28
@Steiner See update answer. There's not much else you could do without using features of specific shells.
– Kusalananda♦
Mar 31 at 11:33
@Steiner See update answer. There's not much else you could do without using features of specific shells.
– Kusalananda♦
Mar 31 at 11:33
Thank you that answers my question. The suggestion at the end and the links provided are very helpful too!
– Steiner
Mar 31 at 11:43
Thank you that answers my question. The suggestion at the end and the links provided are very helpful too!
– Steiner
Mar 31 at 11:43
@Steiner ... except for using a here-document. Well, there's a thing I didn't think of :-)
– Kusalananda♦
Mar 31 at 18:42
@Steiner ... except for using a here-document. Well, there's a thing I didn't think of :-)
– Kusalananda♦
Mar 31 at 18:42
add a comment |
It works for me :
$ cat bin/test
#! /bin/sh
SOMEFILE=$1
MULTILINE="`cat $SOMEFILE`"
SOMEVAR="blah"
echo "$MULTILINE" | while IFS= read -r SINGLELINE
do
echo "this is a single line: $SINGLELINE"
echo "but accessing this var fails: $SOMEVAR"
done
and
$ bin/test bin/test
this is a single line: #! /bin/sh
but accessing this var fails: blah
this is a single line: SOMEFILE=$1
but accessing this var fails: blah
this is a single line: MULTILINE="`cat $SOMEFILE`"
but accessing this var fails: blah
this is a single line: SOMEVAR="blah"
but accessing this var fails: blah
this is a single line:
but accessing this var fails: blah
this is a single line: echo "$MULTILINE" | while IFS= read -r SINGLELINE
but accessing this var fails: blah
this is a single line: do
but accessing this var fails: blah
this is a single line: echo "this is a single line: $SINGLELINE"
but accessing this var fails: blah
this is a single line: echo "but accessing this var fails: $SOMEVAR"
but accessing this var fails: blah
this is a single line: done
but accessing this var fails: blah
My apologies. In trying to create a minimized sample of the actual issue, i made some errors. I updated the code sample now, and it should reflect the problem correctly now.
– Steiner
Mar 31 at 11:13
add a comment |
It works for me :
$ cat bin/test
#! /bin/sh
SOMEFILE=$1
MULTILINE="`cat $SOMEFILE`"
SOMEVAR="blah"
echo "$MULTILINE" | while IFS= read -r SINGLELINE
do
echo "this is a single line: $SINGLELINE"
echo "but accessing this var fails: $SOMEVAR"
done
and
$ bin/test bin/test
this is a single line: #! /bin/sh
but accessing this var fails: blah
this is a single line: SOMEFILE=$1
but accessing this var fails: blah
this is a single line: MULTILINE="`cat $SOMEFILE`"
but accessing this var fails: blah
this is a single line: SOMEVAR="blah"
but accessing this var fails: blah
this is a single line:
but accessing this var fails: blah
this is a single line: echo "$MULTILINE" | while IFS= read -r SINGLELINE
but accessing this var fails: blah
this is a single line: do
but accessing this var fails: blah
this is a single line: echo "this is a single line: $SINGLELINE"
but accessing this var fails: blah
this is a single line: echo "but accessing this var fails: $SOMEVAR"
but accessing this var fails: blah
this is a single line: done
but accessing this var fails: blah
My apologies. In trying to create a minimized sample of the actual issue, i made some errors. I updated the code sample now, and it should reflect the problem correctly now.
– Steiner
Mar 31 at 11:13
add a comment |
It works for me :
$ cat bin/test
#! /bin/sh
SOMEFILE=$1
MULTILINE="`cat $SOMEFILE`"
SOMEVAR="blah"
echo "$MULTILINE" | while IFS= read -r SINGLELINE
do
echo "this is a single line: $SINGLELINE"
echo "but accessing this var fails: $SOMEVAR"
done
and
$ bin/test bin/test
this is a single line: #! /bin/sh
but accessing this var fails: blah
this is a single line: SOMEFILE=$1
but accessing this var fails: blah
this is a single line: MULTILINE="`cat $SOMEFILE`"
but accessing this var fails: blah
this is a single line: SOMEVAR="blah"
but accessing this var fails: blah
this is a single line:
but accessing this var fails: blah
this is a single line: echo "$MULTILINE" | while IFS= read -r SINGLELINE
but accessing this var fails: blah
this is a single line: do
but accessing this var fails: blah
this is a single line: echo "this is a single line: $SINGLELINE"
but accessing this var fails: blah
this is a single line: echo "but accessing this var fails: $SOMEVAR"
but accessing this var fails: blah
this is a single line: done
but accessing this var fails: blah
It works for me :
$ cat bin/test
#! /bin/sh
SOMEFILE=$1
MULTILINE="`cat $SOMEFILE`"
SOMEVAR="blah"
echo "$MULTILINE" | while IFS= read -r SINGLELINE
do
echo "this is a single line: $SINGLELINE"
echo "but accessing this var fails: $SOMEVAR"
done
and
$ bin/test bin/test
this is a single line: #! /bin/sh
but accessing this var fails: blah
this is a single line: SOMEFILE=$1
but accessing this var fails: blah
this is a single line: MULTILINE="`cat $SOMEFILE`"
but accessing this var fails: blah
this is a single line: SOMEVAR="blah"
but accessing this var fails: blah
this is a single line:
but accessing this var fails: blah
this is a single line: echo "$MULTILINE" | while IFS= read -r SINGLELINE
but accessing this var fails: blah
this is a single line: do
but accessing this var fails: blah
this is a single line: echo "this is a single line: $SINGLELINE"
but accessing this var fails: blah
this is a single line: echo "but accessing this var fails: $SOMEVAR"
but accessing this var fails: blah
this is a single line: done
but accessing this var fails: blah
answered Mar 31 at 11:11
RedocTsujRedocTsuj
1
1
My apologies. In trying to create a minimized sample of the actual issue, i made some errors. I updated the code sample now, and it should reflect the problem correctly now.
– Steiner
Mar 31 at 11:13
add a comment |
My apologies. In trying to create a minimized sample of the actual issue, i made some errors. I updated the code sample now, and it should reflect the problem correctly now.
– Steiner
Mar 31 at 11:13
My apologies. In trying to create a minimized sample of the actual issue, i made some errors. I updated the code sample now, and it should reflect the problem correctly now.
– Steiner
Mar 31 at 11:13
My apologies. In trying to create a minimized sample of the actual issue, i made some errors. I updated the code sample now, and it should reflect the problem correctly now.
– Steiner
Mar 31 at 11:13
add a comment |
Thanks for contributing an answer to Unix & Linux Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f509714%2fiterate-through-multiline-string-line-by-line%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Why can you not use
bash
? (add to your question)– ctrl-alt-delor
Mar 31 at 10:54
I can not reproduce your issue using
/bin/sh
on a BSD system. There is nothing in this code that would requirebash
.– Kusalananda♦
Mar 31 at 10:57
My apologies. In trying to create a minimized sample of the actual issue, i made some errors. I updated the code sample now, and it should reflect the problem correctly now. The example indeed does not require Bash.
– Steiner
Mar 31 at 11:09
@Steiner In fact, it would have the same issue in
bash
.– Kusalananda♦
Mar 31 at 11:21
3
There is no Bourne shell on the BSDs. Nor is the Bourne shell standard. Do not conflate the Bourne shell with a POSIX-conformant
sh
.– JdeBP
Mar 31 at 11:29