You are not logged in.
I have a file containing words on each line:
word1
word2
I want to merge these words in a string like this:
$ while read i; do mystr+=$i; done < file
$ echo $mystr
word1word2
Now if I do
$ unset mystr
$ cat file | while read i; do mystr+=$i; done
$ echo $mystr
$mystr is empty, although both of the following work as I expect they should:
$ while read i; do echo $i; done < file
word1
word2
$ cat file | while read i; do echo $i; done
word1
word2
Why is the pipe not working?
Last edited by tethys (2024-09-09 19:10:04)
Offline
Because the pipe introduced a new subshell.
Offline
Also, don't loop when you don't need to:
mystr=$(tr -d '\n' file)
Though if you don't really need newlines removed (or if replacing them with spaces would suffice) then this could be even simpler.
Note if this is just a simplified example and you have a more complicated loop that you want to feed a file to, but you also want the file listed at the start of the loop, the following syntax is what you'd use:
# redacted bad code
Last edited by Trilby (2024-09-09 22:06:37)
"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman
Offline
Thank you both for your answers.
I was not aware that in the example with the pipe the loop is executed in a subshell and the variable is lost.
Marked as solved!
Offline
while read var < file; do mystr=$mystr$var done # mystr is properly set here
This keeps reading the first line of `file` on each iteration, infinitly (at least in bash, zsh, dash, and my understanding of the shell).
I think this is what you meant:
while read var; do
mystr=$mystr$var
done < file
Offline
Oops! You're right. But your code block is not what I meant - that's what I thought the OP might be trying to avoid. I feel sure that there was a way to put the input redirection at the top of the loop without a subshell though ... but at the moment I'm blanking on how.
"UNIX is simple and coherent" - Dennis Ritchie; "GNU's Not Unix" - Richard Stallman
Offline
Do you want to merge all lines into a single line? You can do it with
$ tr -d '\n' < file
Or join them in pairs, i.e. append even lines to odd lines?
$ sed '{N;s/\n//;}' < file
Offline