To summarize the parameters for using read at the end of the [conceptual equivalent] pipeline in POSIX-like wrappers:
Recall: in bash, by default and in strictly compatible POSIX shells, all commands in the pipeline are always executed in a subshell , so the variables that they create or modify will not be visible to the current shell (will not exist after the pipeline completes).
The following cover bash , ksh , zsh and sh ([mainly] shells for POSIX functions only, such as dash ) and show ways to avoid creating a subshell to save variables created / modified with read .
If the minimum version number is not specified, suppose that even "fairly old" versions are supported (such functions have existed for a long time, but I donβt know exactly when they were introduced.
Note that as an [POSIX-compatible] alternative to the solutions below, you can always capture the output of a command in a [temporary] file and then pass it to read as < file , which also avoids subnets.
ksh and zsh : no workaround / configuration change required at all:
read inline is launched by default in the current shell when used as the last command in the pipeline.
Apparently, ksh and zsh by default run any command at the last stage of the pipeline in the current shell.
Observed in ksh 93u+ and zsh 5.0.5 .
If you know specifically in which version this feature was introduced, let me know.
#!/usr/bin/env ksh
bash 4.2+ : use the lastpipe shell option
In bash version 4.2 or later, enabling the lastpipe wrapper lastpipe makes the last pipeline segment work in the current wrapper, allowing reads to create visible variables for the current wrapper.
#!/usr/bin/env bash shopt -s lastpipe
In short, process substitution is a way for command output to act as a temporary file.
out= while read -r var; do out+="$var/" done < <(printf '%s\n' one two three)
out= while read -r var; do out+="$var/" done <<< "$(printf '%s\n' one two three)"
Note the need for double quotation marks for command substitution to protect its output from shell extensions .
#!/bin/sh out= while read -r var; do out="$out$var/" done <<EOF
Note that by default you need to put the trailing delimiter - EOF , in this case - at the very beginning of the line and that no characters should follow it.