6

Is it know that most shebang implementations will support a single parameter so if you have something like

#!/usr/bin/env some-tool-accepting-yaml param1 param2
... (yaml body)

It will now work as expected because it will call the tool with "param1 param2" argument instead of splitting it into two arguments.

It seems that one workaround practice is to use something like:

#!/bin/sh
arbitrary_long_name==0 "exec" "/usr/bin/gawk" "--re-interval" "-f" "$0" "$@"

Now this approach would make YAML-based script invalid due to the 2nd line, so the only acceptable workaround would be one that is also a comment, starting with "#" too.

Is there a way to bypass this issue too?

sorin
  • 161,544
  • 178
  • 535
  • 806
  • 1
    which is the executable to launch is it `python` ? because there's also this related question : https://stackoverflow.com/questions/17458528/why-does-this-snippet-with-a-shebang-bin-sh-and-exec-python-inside-4-single-q – Nahuel Fouilleul Jul 21 '17 at 12:44
  • The workaround you are quoting is for awk, not python. – rici Jul 21 '17 at 13:34
  • 2
    Are you interested in a workaround for YAML, or a general solution? In the former case, please tell us what executable should ultimately consume the content of the file? – randomir Jul 21 '17 at 13:36
  • Workaround for YAML, I already have 3 tools that are using YAML. – sorin Jul 21 '17 at 18:50

2 Answers2

3

A general solution without using polyglot scripts

launcher.sh

#!/bin/bash

# first argument to be split
if [[ $- != *f* ]]; then reset=1; fi
set -f
arg=( $1 )
shift
if [[ $reset = 1 ]]; then set +f; fi

# other arguments
arg+=("$@")

# launch command
exec "${arg[@]}"

script

#!/path/to/launcher.sh interpreter opts
Nahuel Fouilleul
  • 18,726
  • 2
  • 31
  • 36
0

There is no generic solution for this problem(unless you are on MacOSX, which can pass multiple parameters in the shebang line), but for particular combinations of the requirements you can use shell tricks, like:

#!/bin/sh
exec yamllint -f colored --no-warnings ${1:+-c ${1}} - <<...
---
(YAML document)
...

We are using HERE-doc feature of the shell and YAML end-of-document marker ... to denote where the shell input ends. Please note, that that would work only with the commands that can accept their input from the STDIN.

If the some-tool needs filename as the input parameter, you can (ab)use bash in-place file implementation feature, where output of the command is passed through the mapped file descriptor:

#!/bin/bash
exec ansible-playbook --ask-become-pass ${1:+--extra-vars hostname=${1}} <(tail +3 ${0})
---
- hosts: all
  gather_facts: false
  become: true
  vars_prompt:
    - name: hostname
      prompt: "Hostname"
      private: no

  tasks:
(YAML document)

We are passing the output of the tail command, skipping first 3 lines of this file through the /dev/fd/xx file descriptor, which is treated as a normal readable file by ansible-playbook.

Timur Bakeyev
  • 296
  • 4
  • 4