3

I have this mini bash script

#!/usr/bin/env bash

go run <(cat <<EOF
package main

import "log"

func main(){
  log.Println("here 123")
}
EOF
)

go run takes a file path argument, often times just something like:

go run main.go

is there a way to fool go into running my inline program? I am currently getting this error:

package /dev/fd/63: import "/dev/fd/63": cannot import absolute path

muru
  • 72,889

1 Answers1

3

Like all high-brow tools and languages, go is not easily amenable to be used in ways its authors did not like or foresee.

In this case, go does not want to have anything to do with with paths not ending in *.go.

A solution may be to use a temporary file named *.go:

gorun(){
  t=$(mktemp -d) && cat > "$t/in.go" && go run "$t/in.go"
  e=$?; rm -fr "$t"; return "$e"
}

gorun <<'EOT'
...
EOT

I cannot use just mktemp /tmp/XXXXXXX.go above; that will silently create a file named exactly /tmp/XXXXXXX.go on BSD, where mktemp only supports trailing Xs. Also, I cannot assume that /tmp exists, is writable and is the place where temporary files are created by default.


This point is already moot, but go also has problems with pipes and other non-regular files, so a process substitution wouldn't have worked anyway:

% ln -s /dev/fd/3 fd3.go
% go run fd3.go 3<<<'package main; func main(){}'
  // OK
% go run fd3.go 3< <(echo 'package main; func main(){}')
# command-line-arguments
./fd3.go:1:1: syntax error: package statement must be first
% cat fd3.go 3< <(echo 'package main; func main(){}')
package main; func main(){}
  // WTF?
% mkfifo fifo.go
% go run fifo.go &
[1] 8849
% echo 'package main; import "log"; func main(){log.Println("yuck!")}' > fifo.go
   // if at first you don't succeed ...
% echo 'package main; import "log"; func main(){log.Println("yuck!")}' > fifo.go
% 2020/02/06 11:21:53 yuck!

[1]+  Done                    go run fifo.go
  • yeah a short inline program is nice sometimes, don't have to wonder what it does, it's right there – Alexander Mills Feb 06 '20 at 20:23
  • You can give mktemp a "template", like mktemp XXXXXX.go creates something like nVF1Ja.go. That should clean up your function a bit. – glenn jackman Feb 06 '20 at 22:04
  • @glennjackman no, I cannot assume that the current working dir is writable, that mktemp supports non-trailing XXXs or that /tmp exists, is writable and is the place where tempfiles are created by default. Or that mktemp supports the TMPDIR envvar. But that mv was subject to a symlink attack, thanks for making me rethink it ;-) –  Feb 07 '20 at 10:17
  • @glennjackman I haven't make up that stuff for the sake of the argument: mktemp XXXXXX.go will create a file named exactly XXXXXX.go on FreeBSD, there's no /tmp on Android and /tmp is not the default tmpdir on MacOS. And dropping stuff inside cwd or the homedir is gross, even if it may work. –  Feb 07 '20 at 10:27