2

Using pipes, one can create files with simple shell built-ins.

{ echo "#!/bin/bash" \
  echo "echo Hello, World!" \
} > helloworld.sh

With chmod these can then be made executable.

$ chmod 755 helloworld.sh
$ ./helloworld.sh
Hello, World!

I wonder whether it is possible to save the chmod step. Already, I found that umask cannot do the job. But perhaps someone knows an environment variable, bash trick, program to pipe through or other neat way to do it.

Is it possible to have the file created with the executable bit already set?

5
  • Have you tried touch file; chmod u+x file; dostuff >> file; ./file?
    – DopeGhoti
    Mar 14, 2017 at 20:14
  • why do you want to skip the chmod step?
    – schaiba
    Mar 14, 2017 at 20:17
  • The purpose to skip chmod is to reduce changes to a single point. When the file name or path should later change, the change would than only affect this single line. Defining a variable keeping it would be an alternative, but add an otherwise unnecessary line.
    – XZS
    Mar 14, 2017 at 20:32
  • 2
    you're already using the filename twice (creation, execution); a variable seems reasonable to me.
    – Jeff Schaller
    Mar 14, 2017 at 20:37
  • I often see this situation in packaging software for Linux distributions. A small wrapper start script around an executable (for example in /opt) has to be created via pipe, then made executable, which makes exactly these two uses. The one who calls the script then, is the user who installed the package.
    – XZS
    Mar 14, 2017 at 20:44

2 Answers 2

3

It is not possible to create an executable file solely with a shell redirection operator. There is no portable way, and there is no way in bash either (in the source code, you can see that redirection calls do_redirection_internal which calls redir_open with the parameter mode set to 0666, and this in turn calls open with this mode).

You're calling a shell command anyway, so add ; chmod +x … somewhere in it. There's absolutely nothing wrong with that. One more line of code is not a problem. You need to do three things (create a file with some given content, make the file executable, execute it), so write three lines.

There is a relatively obscure shell command that can create an executable file with some specified content: uudecode. But I would not recommend using it: it requires the input to be passed in a non-readable format, it bypasses the user's umask, and it's obscure.

A sane alternative is to call bash /the/script instead of chmod +x /the/script && chmod +x, if you know what interpreter to execute the file with.

2
  • The uudecode utility is not "relatively obscure" or "obscure". Been around in distributions since BSD 4.0 and is still used by many.
    – fpmurphy
    Mar 15, 2017 at 0:47
  • @fpmurphy1, I think it's safe to say it's "relative obscure" nowadays, with MIME used on email, and proper news servers quite rare.
    – ilkkachu
    Mar 17, 2017 at 15:18
2

A function to create an executable shell script from piped input:

pipe2script() { touch "$1" ; chmod +x "$1" ; \
                echo '#!'"$(which ${2:-bash})"  > "$1" ; cat >> "$1" ; }

Use pipe2script to pipe two lines of text to foo.sh:

printf 'echo hello world\necho bye\n' | pipe2script foo.sh

This outputs a new executable file, foo.sh:

$ ls -log foo.sh 
-rwxrwxr-x 1 38 Mar 18 09:05 foo.sh

Running cat foo.sh shows:

#!/bin/bash
echo hello world
echo bye

Run it:

./foo.sh

Output:

hello world
bye

The pipe2script function defaults to using bash, but it can take a second argument of any other shell name, i.e. dash, zsh, ksh93, python, etc. Example using the fish shell's math command:

printf 'math "99^33"\n' | pipe2script foo.fish fish

Running cat foo.fish shows:

#!/usr/bin/fish
math "99^33"

Output of ./foo.fish:

717730532598275105894510914059816191752829524684539601273450723299

Edit a copy of a script:

sed '2,${s/.*/echo & | jethro/e;s/ / "/;s/$/"/}' foo.sh | pipe2script foojc.sh

Output when run:

$ ./foojc.sh 
howdy world
y'all come back now, heah?
1
  • I chose Gilles' answer as the "correct" one as it provides a method that works within one single pipe, which was the "trick" I sought. This answer is very useful nonetheless and would be the one with more practical use.
    – XZS
    Mar 23, 2017 at 19:49

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .