git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH v6 2/3] Documentation: alias: add notes on shell expansion

From
Junio C Hamano <gitster@pobox.com>
Date
May 26, 2024, 23:26 UTC
Message-ID
<xmqqa5kcduis.fsf@gitster.g>
In-Reply-To
<20240525234454.1489598-2-iwienand@redhat.com>
Ian Wienand <iwienand@redhat.com> writes:
Show 9 quoted lines
> +* If the shell alias is the full path to a binary, it will be executed
> +  directly with any arguments as positional arguments.
> +* If the alias contains any white-space or reserved characters, it
> +  will be considered an inline script and run as an argument to `sh
> +  -c`.
> +* When running as a script, if arguments are provided to the alias
> +  call, Git makes them available to the process by appending "$@" to
> +  the alias shell command.  This is not appended if arguments are not
> +  provided.
These are not technically wrong per-se.
Show 5 quoted lines
> +** For "simple" commands, such as calling a single binary
> +  (e.g. `alias.myapp = !myapp --myflag1`) this will result in any
> +  arguments becoming additional regular positional arguments to the
> +  called binary, appended after any arguments specified in the aliased
> +  command.

But the single-command script still receives the arguments in argv[], so what the alias command has to do is the same. The earlier ones that are "not technically wrong" are merely implemenation detail.

In a single command case, e.g., "[alias] single = !one", you may write

    #!/bin/sh
    echo "$1" | grep "$2"
in 'one' script, and "git single 1 2" will be turned into
    start_command: one 1 2

i.e. one receives two arguments in argv[]. It is an implementation detail that we can bypass "sh" or "-c" or "$@"

If you write exactly the same thing like
    $ git -c 'alias=single=!one ' single 1 2
you'll instead see
    start_command: /bin/sh -c 'one' "$@" "one " 1 2

because the trailing SP in the alias disables the optimization to bypass a more generic 'sh -c ... "$@"' construction. What gets run is an equivalent of the reader saying

    $ /bin/sh -c 'one "$@"' "one " 1 2
bypassing git from the command line.

What the script (one) has to write does not change at all either case.

As I keep saying over multiple iterations, the above three bullet points stress too much on the minute implementation detail while failing to tell readers that the end-user alias receives the rest of the command line as arguments.

> +** Care should be taken if your alias script has multiple commands
> +   (e.g. in a pipeline), references argument variables, or is
"argument variables" -> "arguments".
> +   otherwise not expecting the presence of the appended `"$@"`.  

"otherwise not expecting" is SIMPLY BUGGY but the readers may not understand it unless you tell them that the arguments are fed to their aliased command by appending them.

When you look at the implementation detail of "sh -c '... $@' - $ARGS" as something to fight against, readers would lose sight to see the crux of the problem they are trying to solve. I think it is a wrong way to frame the issue. The problem readers are solving when coming up with their own alias is this:

    How would one write a single-liner that can take arguments
    appended at the end?

I think giving that to the readers upfront, i.e. "when you write an alias, you are forming a single-liner that takes arguments appended at the end", would go a long way without having them lose sight in the implementation details of "sometimes args directly come in argv[], sometimes your alias is wrapped in "sh -c" and "$@" is used. They do the same thing to feed the arguments to your script.

Going back that 'one' example, if 'echo "$1" | grep "$2"' was what you wanted to run, how would you write a single-liner that does

    echo "$1" | grep "$2"

and can take its arguments at the end? You do *not* want to see your invocation of the alias

    $ git single 1 2
turn into 
    $ echo "$1" | grep "$2" 1 2

of course, and remember, "$@" is merely an implementation detail that the end-users do not need to see.

Of course the simplest one-liner, if you had the "one" script already stored in the file, is to say

    $ one                                  1 2

i.e. "[alias] single = !one". But calling that a "single-liner" is cheating.

You can do one of two easy things.
    $ sh -c 'echo "$1" | grep "$2"' -      1 2
    $ e(){ echo "$1" | grep "$2"; };e      1 2

The earlier string (before "1 2" is appended) of either of these gives you "a single-liner that takes arguments at the end" that does the "echo the first one, pipe it to grep that looks for the second one", which you would make the body of the alias. If the reader understands the earlier example that stores it in a file, the former is more mechanical and straight-forward rewrite of it. The latter may be a bit more convoluted, but says the same thing in the same number of letters.

HTH.
Previous: Ian WienandNext: Ian Wienand
Message 36 of 43 in “alias: document caveats and add trace of prepared command”
  1. alias: document caveats and add trace of prepared commandIan Wienand, May 22, 2024
  2. Eric SunshineMay 22, 2024
  3. Junio C HamanoMay 22, 2024
  4. Ian WienandMay 23, 2024
  5. 1/3 Documentation: alias: rework notes into pointsIan Wienand, May 23, 2024
  6. 2/3 Documentation: alias: add notes on shell expansionIan Wienand, May 23, 2024
  7. 3/3 run-command: show prepared commandIan Wienand, May 23, 2024
  8. Eric SunshineMay 23, 2024
  9. Ian WienandMay 23, 2024
  10. 1/3 Documentation: alias: rework notes into pointsIan Wienand, May 23, 2024
  11. 2/3 Documentation: alias: add notes on shell expansionIan Wienand, May 23, 2024
  12. 3/3 run-command: show prepared commandIan Wienand, May 23, 2024
  13. Junio C HamanoMay 23, 2024
  14. Junio C HamanoMay 23, 2024
  15. Junio C HamanoMay 24, 2024
  16. Ian WienandMay 24, 2024
  17. Junio C HamanoMay 24, 2024
  18. Ian WienandMay 24, 2024
  19. Junio C HamanoMay 24, 2024
  20. Ian WienandMay 25, 2024
  21. Junio C HamanoMay 23, 2024
  22. 1/3 Documentation: alias: rework notes into pointsIan Wienand, May 24, 2024
  23. 2/3 Documentation: alias: add notes on shell expansionIan Wienand, May 24, 2024
  24. 3/3 run-command: show prepared commandIan Wienand, May 24, 2024
  25. Junio C HamanoMay 24, 2024
  26. Junio C HamanoMay 24, 2024
  27. Ian WienandMay 25, 2024
  28. 1/3 Documentation: alias: rework notes into pointsIan Wienand, May 25, 2024
  29. 2/3 Documentation: alias: add notes on shell expansionIan Wienand, May 25, 2024
  30. 3/3 run-command: show prepared commandIan Wienand, May 25, 2024
  31. Junio C HamanoMay 25, 2024
  32. Junio C HamanoMay 25, 2024
  33. Ian WienandMay 25, 2024
  34. 1/3 Documentation: alias: rework notes into pointsIan Wienand, May 25, 2024
  35. 2/3 Documentation: alias: add notes on shell expansionIan Wienand, May 25, 2024
  36. Junio C HamanoMay 26, 2024
  37. Ian WienandMay 27, 2024
  38. 3/3 run-command: show prepared commandIan Wienand, May 25, 2024
  39. Junio C HamanoMay 26, 2024
  40. 1/3 Documentation: alias: rework notes into pointsIan Wienand, May 27, 2024
  41. 2/3 Documentation: alias: add notes on shell expansionIan Wienand, May 27, 2024
  42. Junio C HamanoMay 27, 2024
  43. 3/3 run-command: show prepared commandIan Wienand, May 27, 2024

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.