Define bash aliases to run git as specific user - bash

Is it possible to define a function in a bash script which generically defines git-aliases for different users in order to let users apply their changes on a shared system so that the commits contains their username and email?
alias git_as_user1='GIT_AUTHOR_NAME="User1_pre User1_sur" GIT_AUTHOR_EMAIL="user1#company.de" GIT_SSH="/home/account/ssh_user_wrapper.sh" GIT_COMMITTER_NAME=$GIT_AUTHOR_NAME GIT_COMMITTER_EMAIL=$GIT_AUTHOR_EMAIL git'
I came up with the following function, but it does not evaluate args at the time of the alias definition but later on, when the alias is called.
This is unintended and renders the approach useless.
function alias_git_as ()
{
alias git_as_$1='GIT_AUTHOR_NAME=$1 GIT_AUTHOR_EMAIL=$2
}
In .basrc:
alias_git_as "login" "Surname Prename" "user#company.de"
-> Won't work !!! -> Defines the alias git_as_login, but the second and third arg are dismissed. When a certain user runs git_as_login from his terminal he would need to pass "Surname Prename" "user#company.de" again. But the args should be captured at time the alias is defined.

Two issues:
You use single quotes, but those suppress expansion; to make expansion happen early, you need double quotes instead.
Your original code only takes two arguments, but your example usage uses three.
Also, to make this work with names with spaces, we use the bash 5.x feature ${var#Q} below.
# define the function
alias_git_as() { alias "git_as_$1=GIT_AUTHOR_NAME=${2#Q} GIT_AUTHOR_EMAIL=${3#Q}"; }
# use the function
alias_git_as "login" "Surname Prename" "user#company.de"
# use the invoked alias
git_as_login
See this working at https://ideone.com/PV09NG
A version that's compatible with older versions of bash while still retaining support for unusual author names may instead look like:
alias_git_as() {
local alias_def
printf -v alias_def 'git_as_%s=GIT_AUTHOR_NAME=%q GIT_AUTHOR_EMAIL=%q' "$1" "$2" "$3"
alias "$alias_def"
}

Related

How can I adjust my bash function such that I can omit the double-quotes?

Throughout the day, I type something like this frequently:
git stash push -u -m "some phrase as a message"
I would prefer to type instead:
stpu some phrase as a message
So with help from this answer, I created a function in my ~./bashrc:
function stpu() {
git stash push -u -m "${#}"
}
Now I'm able to type stpu "some phrase as a message", which is pretty close to what I want.
How can I adjust my function such that I can omit the double-quotes?
I've tried many different variations (adding more double-quotes that are escaped, adding single-quotes, etc) but haven't gotten it to work.
You can sometimes omit the quotes if you use "$*" instead of "$#"
This will concatenate all your arguments together into a single string, separated with spaces (by default; the first character in IFS, if it's been overridden). -m expects a single string to follow it (instead of a separate argument per word), so this is exactly what it wants.
This is not reliable, and it's better to just use the quotes.
Security
Consider as an example if you want to use the commit message: Make $(rm -rf ~) safe in an argument name for a security fix. If this string is unquoted (or double quoted), the command is executed before your function is ever started (which makes sense: a function can't be called until after its argument list is known), so there's nothing your function can do to fix it. In this context, using single quotes to prevent the command substitution from taking place is the correct and safe practice.
(To single-quote a string that contains single quotes, consider using ANSI C-like strings: $'I\'m a single-quoted string that contains a single quote')
Correctness
Or, as another example: Process only files matching *.csv -- if it's not quoted, the *.csv can be replaced with a list of CSV files that exist in the directory where you ran the command. Again, this happens before your function is ever started, so nothing inside the function can prevent it.

How do I pass a command parameter in a variable holding the command?

I want to produce the same output as this:
bash utilities.bash "is_net_connected"
But I don't know how to pass "is_net_connected" if command and file is stored in a variable like this:
T=$(bash utilities.bash)
I've tried these but it doesn't seem to work. It's not picking up ${1} in utilities.bash.
$(T) "is_net_connected"
$(T "is_net_connected")
Not the best way to inport but I'm trying to avoid cluttering my main script with function blocks.
T=$(bash utilities.bash) doesn't save the command; it runs the command and saves its output. You want to define a function instead.
T () {
bash utilities.bash "$#"
}
# Or on one line,
# T () { bash utilities.bash "$#"; }
Now
T "is_net_connected"
will run bash utilities.bash with whatever arguments were passed to T. In a case like this, an alias would work the same: alias T='bash utilities.bash'. However, any changes to what T should do will probably require switching from an alias to a function anyway, so you may as well use the function to start. (Plus, you would have to explicitly enable alias expansion in your script.)
You might be tempted to use
T="bash utilities.bash"
$T is_net_connected
Don't be. Unquoted parameter expansions are bad practice that only work in select situations, and you will get bitten eventually if you try to use them with more complicated commands. Use a function; that's why the language supports them.

Create shell alias with value from current path

I want to create a shell alias which would run
command ew --constantswitch --anotherconstantswitch <name>
Now the value name needs to be extracted from the current path. the current path looks like this
[username#path-to-shell-xxxxxxxx]/path/to/directory/with/name%
How can I create an alias such that when I run aliasX it will
Extract the name from current path (which is last value of the prompt)
Add this path to the command above and execute.
An alias may not be competent for the job, but a function surely do. Try this code:
myfunc() {
command ew --constantswitch --anotherconstantswitch "${PWD##*/}"
}
The trick is ${PWD##*/}. You know the automatic variable $PWD is exactly what you get when you run pwd, as well as Bash's builtin string substitution ${var##pattern} that removes pattern from the left of the variable with maximum match. So ${PWD##*/} removes everything except the name after the last slash, which as you described is what you're looking for.
In practice, a function is more versatile than an alias. If you still need to add extra arguments to the command, append "$#" to the end of the command inside the function, so any argument that you pass to the function will be forwarded to the command.
Since you're not trying to do anything involving arguments, an alias is actually possible:
alias aliasX='echo "${PWD##*/}"'
This will print the current directory name when you use aliasX. Or, using your example:
alias aliasX='command ew --constantswitch --anotherconstantswitch "${PWD##*/}"'
Notice that the alias must be in single quotes or $PWD will expand when you define it instead of when you use it.
For anything slightly more complex, you should use a function instead of an alias, as shown in iBug's answer.

How can I make a bash alias for smem -ntkP '[m]yprocess'?

I would like to make an alias for smem tool.
I need to have the first letter of the process between hooks to let smem subtract himself from the calculation.
So, I would like something like:
myalias chromium
(which invokes the following command => smem -ntkP '[c]hromium')
I really don't know how to do that. I searched the answer before I ask my question.
Don't use aliases. This is a FAQ. Use a function.
sm () {
smem -ntkP "[${1:0:1}]${1:1}"
}
Unlike aliases, functions take arguments, just like scripts; so $1 is the first argument to the function, and ${1:0:1} is the first character of that argument. (The ${variable:offset:length} substring substitution is a Bash extension.)
Continuing from the comment, If you would like to alias chromium and have it invoke smem -ntkP '[c]hromium', then you could do something similar to:
alias chromium='smem -ntkP [c]hromium'
though it is unclear what purpose your single-member character-class [C] plays in that role... and which probably makes more sense written as:
alias chromium='smem -ntkP chromium'
note: you can include the alias in your ~/.bashrc or in the system-wide equivalent on your system to have the alias always available. Be careful when overwriting executable names like chromium with a second alias (e.g. alias chromium='...') It is better in most cases to choose a name that doesn't conflict (and requires less typing) say chrom='...'

Exclamation point in bash function name - should I?

I'm writing a bash script and it's really convenient to use an exclamation point in a function name.
Example:
function hello! {
echo goodbye
}
function hello {
echo hello
}
And it works!
After looking through the specs, I found this:
name
A word consisting solely of letters, numbers, and underscores, and beginning with a letter or underscore. Names are used as shell variable and function names. Also referred to as an identifier.
I feel like I'm breaking the rules here. Is this wrong? Will this mess something up in the future? What's actually going on?
Since it violates the Bash spec, I'd say you're exploiting a bug in Bash, so your code might not work when the bug is fixed. Drop the !
Out of burning curiousity, why is it so much more convenient to use the exclamation point in your function name?
Generally, for portability reasons, you may not want to use the bang; just because the interpreter on that particular OS accepts it, if you need to deploy that script elsewhere, other interpreters of slightly different flavors/versions may not be as accepting.
I'm not sure about the implications in this case, but if the specification states something this clearly, I'd say anything beyond that is undefined behavior and should be avoided.
It's not a good idea to use ! in a function name if you want your code to be portable. bash --posix or invoking bash as "sh" both reject "hello!" as a function name. But I suspect that bash silently permits aberrant function names ("hello?" "hello-" and "hello/" also work, to name a few) because one important use of functions is allowing the user to override normal commands and these commands (e.g. ls, rm, etc.) can contain any sort of character allowed by the filesystem.
Note that "hello!" as a variable name doesn't work.
If your function is meant to be invoked by an user as a command from the terminal, i. e. it's defined in .bashrc, then you could give it a longer name and create an alias with the bang at the end.
Example:
function cd_mkdir {
DEST=$1
mkdir -p "$DEST"
cd "$DEST"
}
alias cd!=cd_mkdir
Now, while in terminal I can invoke this as:
cd! foo/bar/baz
And the foo, bar and baz directories get created if they don't exists.
The exclamation mark at the end is a nice and easy mnemonic of "shouting" the familiar command to be force executed, even if the original variant of the command couldn't.

Resources