40

Previously I used source command like this:

source file_name

But what I'm trying to do is this:

echo something | source

Which doesn't work.

Braiam
  • 35,380
  • 25
  • 108
  • 167
Desmond Hume
  • 2,718
  • 5
  • 21
  • 21

2 Answers2

65

Since source (or .) takes a file as argument, you could try process substitution:

source <(echo something)
nnnmmm
  • 145
  • 6
muru
  • 69,900
  • 13
  • 192
  • 292
  • 1
    That worked, thank you. And Happy New Year! – Desmond Hume Dec 31 '14 at 20:54
  • 1
    @muru This works great. Note that "| source /dev/stdin" has the *appearance* of working, but it'll actually drop all of the variable assignments. Not sure why. Seems solid in theory. It's insanity. – Dustin Oprea Nov 17 '17 at 03:25
  • 7
    @DustinOprea pipes create a subshell, so all those variable assignments never affect the parent shell. – muru Nov 17 '17 at 03:27
  • https://mywiki.wooledge.org/SubShell – MarcH Oct 22 '20 at 00:50
  • Works in Bash: source /dev/stdin <<< "echo 123; X=42; echo 456"; echo $X – Martin Feb 27 '22 at 05:45
  • The question is not about a specific shell so it is important to say that the process substitution `<(command ...)` is not part of the POSIX specification. You can find it in ksh, bash and some other shells. See [What is the portable (POSIX) way to achieve process substitution?](https://unix.stackexchange.com/q/309547/19702). – pabouk - Ukraine stay strong Mar 29 '22 at 07:15
  • @pabouk-Ukrainestaystrong eh... did you miss that `source` isn't part of the POSIX specification either? – muru Mar 29 '22 at 10:38
  • That makes it even worse :D The `.` command is part of POSIX and `source` is just a more readable alias for it. See https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#dot – pabouk - Ukraine stay strong Mar 29 '22 at 12:01
  • @pabouk-Ukrainestaystrong I'm not sure how it makes it worse, since `source` is explicitly in the question, so this question at least isn't about POSIX shells – muru Mar 29 '22 at 12:02
  • I wonder why `sudo cat /root/.bashrc | bash` didn't work. But your command worked perfectly. – Shayan Mar 02 '23 at 10:04
11

Your source command requires a file argument. You can get that in some shells with a process substitution, and this is because in the same way the shell replaces...

arg=$(echo hi)

...the echo bit there on the command-line with the subshell's output, in the case of process substitution it replaces the subshell with a named file - usually /dev/fd/62 or something - some link to a file-descriptor. With a pipe the file descriptor is 0 so...

echo 'echo hi' | . /dev/fd/0

... /dev/stdin or whatever as the case may be should work just fine on any linux system - and many others besides. You can also use here-documents similarly:

. /dev/fd/3 3<<HI
$(echo 'echo hi')
HI

You can verify the way your shell handles process substitution, by the way:

(set -x; readlink <(:))

...which prints (in bash):

+ set +x
+ readlink /dev/fd/63
++ :
pipe:[2212581]

...and so we can see that the shell is doing the substitution and readlink is reading from an an anoymous pipe that it opens on file-descriptor 63.

mikeserv
  • 57,448
  • 9
  • 113
  • 229
  • You cannot use a process in a pipe (your example `echo 'echo hi' | . /dev/fd/0`) to make side-effects in the current shell (like setting aliases, environment etc.) because the commands in a pipe are run as child processes and their side-effect are lost when they are finished. – pabouk - Ukraine stay strong Mar 29 '22 at 07:20