Use sed on a string variable rather than a file

I have been told it was possible, but without a single working example, that sed can read from a string variable without need for an input file. I have yet to get it to work. For general safety, I’m writing the $PATH variable to another variable, as I mess with this, because I don’t need other problems to arise until I know exactly how to do this.

Consider the following:

~$x=$PATH
~$sed -i 's/:/ /g' $x

this fails with: No such file or directory.

Here are some others I have tried:

~$ sed -i 's/:/ /g' | (read x) 
sed: no input files
~$ sed -i 's/:/ /g' | (read $x) 
bash: read: `/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games': not a valid identifier
sed: no input files
~$ sed -i 's/:/ /g' | $(read x) 
sed: no input files
~$ sed -i 's/:/ /g' | $(read $x) 
bash: read: `/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games': not a valid identifier
sed: no input files
~$ sed -i 's/:/ /g' < $(read $x) 
bash: read: `/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games': not a valid identifier
bash: $(read $x): ambiguous redirect
~$ sed -i 's/:/ /g' < read $x 
bash: read: No such file or directory
~$ sed -i 's/:/ /g' < (read x) 
bash: syntax error near unexpected token `('
~$ sed -i 's/:/ /g' < $((read x)) 
bash: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games: syntax error: operand expected (error token is "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games")
~$ sed -i 's/:/ /g' < $((read $x)) 
bash: read /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games: division by 0 (error token is "usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games")
~$ sed -i 's/:/ /g' << $((read $x)) 
> ;^C
~$ sed -i 's/:/ /g' << $(read $x)
> ;^C
~$ sed -i 's/:/ /g' $x
sed: can't read /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games: No such file or directory
~$ sed -i 's/:/ /g' < $x
bash: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games: No such file or directory
~$ sed -i 's/:/ /g' < echo $x
bash: echo: No such file or directory
~$ sed -i 's/:/ /g' |  echo $x
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
sed: no input files

Can this even work? I would prefer not to need to write files I don't need just so I can use sed. For this particular example, if ~$x=$PATH ~$sed -i 's/:/ /g' $x actually worked the way I would have hoped, I would get:

/usr/local/sbin /usr/local/bin /usr/sbin /usr/bin /sbin /bin /usr/games /usr/local/games

which I could then assign to a variable, and use in future commands, like ls $x


This has nothing to do with sed as such, it applies to any program that reads standard input. Anyway, what you were looking for is

sed 's/:/ /g' <<<"$PATH"

There's no reason to save in another variable, nothing you do this way will affect the value stored in the variable. You need the assignment operator (=) for that. The syntax used above is called a "here string" and is specific to bash, ksh and zsh. It serves to pass a variable's value as input to a program that reads from standard input.

I have written up an answer on U&L that lists all the various shell operators like this one. You might want to have a look.

Note that you could also have done

echo "$PATH" | sed 's/:/ /g' 

Finally, you really don't need sed at all for this. You can do the whole thing in bash directly:

echo "${PATH//:/ }"

The above is a bash replacement construct. Given a variable $var, a pattern pat and a replacement (rep), to replace all occurrences of pat with rep, you would do

echo "${var//pat/rep}"

The same thing with a single slash replaces only the first occurrence:

echo "${var/pat/rep}"

May be:

~$ x="$PATH"
~$ x="$(echo $x | sed 's/:/ /g')"
~$ echo "$x"
/usr/local/bin /usr/bin /bin /usr/local/games /usr/games