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.
Related
On Linux Ubuntu, when you do sudo apt update && sudo apt install perl, it adds the following to the bottom of your ~/.bashrc file (at least, many months later, I think that is what added those lines):
PATH="/home/gabriel/perl5/bin${PATH:+:${PATH}}"; export PATH;
PERL5LIB="/home/gabriel/perl5/lib/perl5${PERL5LIB:+:${PERL5LIB}}"; export PERL5LIB;
PERL_LOCAL_LIB_ROOT="/home/gabriel/perl5${PERL_LOCAL_LIB_ROOT:+:${PERL_LOCAL_LIB_ROOT}}"; export PERL_LOCAL_LIB_ROOT;
PERL_MB_OPT="--install_base \"/home/gabriel/perl5\""; export PERL_MB_OPT;
PERL_MM_OPT="INSTALL_BASE=/home/gabriel/perl5"; export PERL_MM_OPT;
What does this strange syntax do in many of the lines, including in the first line? It appears to be some sort of bash array slicing:
${PATH:+:${PATH}}
The ${PATH} part is pretty straightforward: it reads the contents of the PATH variable, but the rest is pretty cryptic to me.
It's not array slicing; it's a use of one of the POSIX parameter expansion operators. From the bash man page, in the Parameter Expansions section,
${parameter:+word}
Use Alternate Value. If parameter is null or unset, nothing is
substituted, otherwise the expansion of word is substituted.
It's a complex way of making sure that you only add a : to the value if PATH isn't empty to start with. A longer, clearer way of writing it would be
if [ -n "$PATH" ]; then
PATH=/home/gabriel/perl5/bin:$PATH
else
PATH=/home/gabriel/perl5/bin
fi
However, since it if almost inconceivable that PATH is empty when .basrhc is sourced, it would be simpler to just prepend the new path and be done with it.
PATH=/home/gabriel/perl5/bin:$PATH
If PATH actually ended with a :, it would implicitly include the current working directory in the search path, which isn't a good idea for security reasons. Also from the bash man page, in the section on Shell Variables under the entry for PATH:
A zero-length (null) directory name in the
value of PATH indicates the current directory. A null directory
name may appear as two adjacent colons, or as an initial or
trailing colon.
As an aside, it's good to understand what various installers try to add to your shell configuration. It's not always necessary, and sometimes can actively change something you already have configure.
I would much prefer if packages simply printed instructions for what needs to be added to your configuration (and why), and leave it to the user to make the appropriate modifications.
What does this strange syntax do in many of the lines, including in the first line?
It's the ${parameter:+word} form of parameter expansion where word becomes the expanded value if parameter is not unset and not having the value of an empty string (a.k.a. null).
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.
export GOPATH=~/mygo:~/go
export GOBIN=$GOPATH/bin
I expected the $GOBIN equals ~/mygo/bin:~/go/bin but it is ~/mygo:~/go/bin instead.
how could I set them a better way? thx
Solution
export GOPATH=~/mygo:~/go
export GOBIN=${(j<:>)${${(s<:>)GOPATH}/%//bin}}
Explanation
Although whatever program uses GOPATH might interprete it as an array, for zsh it is just a scalar ("string").
In order to append a string (/bin) to every element the string "$GOPATH" first needs to be split into an array. In zsh this can be done with the parameter expansion flag s:string:. This splits a scalar on string and returns an array. Instead of : any other character or matching pairs of (), [], {} or <> can be used. In this case it has to be done because string is to be :.
GOPATH_ARRAY=(${(s<:>)GOPATH)
Now the ${name/pattern/repl} parameter expansion can be used to append /bin to each element, or rather to replace the end of each element with /bin. In order to match the end of a string, the pattern needs to begin with a %. As any string should be matched, the pattern is otherwise empty:
GOBIN_ARRAY=(${GOPATH_ARRAY/%//bin})
Finally, the array needs to be converted back into a colon-separated string. This can be done with the j:string: parameter expansion flag. It is the counterpart to s:string::
GOBIN=${(j<:>)GOBIN_ARRAY}
Fortunately, zsh allows Nested Substitution, so this can be done all in one statement, without intermediary variables:
GOBIN=${(j<:>)${${(s<:>)GOPATH}/%//bin}}
Alternative Solution
It is also possible to do this without parameter expansion flags or nested substitution by simply appending /bin to the end of the string and additionally replace every : with /bin::
export GOBIN=${GOPATH//://bin:}/bin
The ${name//pattern/repl} expansion replaces every occurence of pattern with repl instead of just the first like with ${name/pattern/repl}.
This would also work in bash.
Personally, I feel that it is a bit "hackish", mainly because you need to write /bin twice and also because it completely sidesteps the underlying semantics. But that is only personal preference and the results will be the same.
Note:
When defining GOPATH like you did in the question
export GOPATH=~/mygo:~/go
zsh will expand each occurence of ~/ with your home directory. So the value of GOPATH will be /home/kevin/mygo:/home/kevin/go - assuming the user name is "kevin". Accordingly, GOBIN will also have the expanded paths, /home/kevin/mygo/bin:/home/kevin/go/bin, instead of ~/mygo/bin:~/go/bin
This could be prevented by quoting the value - GOPATH="~/mygo:~/go" - but I would recommend against it. ~ as synonym for the home directory is not a feature of the operating system and while shells usually support it, other programs (those needing GOPATH or GOBIN) might not do so.
This may be poorly titled as I'm not fully sure what the process is called.
Basically I want to get only the last part of a symlink path, and I'm trying to use the same method I use with PWD.
For example:
if I do
PWD
it prints
/opt/ct/mydir
if I do
echo ${PWD##*/}
it prints only the last part
mydir
So using that design I can do
readlink mysymlink
which gives
/opt/ct/somedir
and I can do
TMP=$(readlink mysymlink)
echo ${TMP##*/}
and it will print
somedir
So now how can I combine that last part into one line like
TMP=$(readlink mysymlink && echo ${TMP##*/})
???
The example I show gives me 2 concatenated results.. one with the full path and one with just the part I want. I only want that last directory.
I also tried
TMP=${ $(readlink mysymlink)##*/}
to no avail
Variable substitution suffixes can only be used with variables, not command substitutions. You either have to set the variable and modify it in separate statements, as in your first attempt, or use additional command substitutions:
TMP=$(basename $(readlink))
I have a script which contains the following line:
propFile="${0%/*}/anteater.properties"
What does "${0%/*}" mean?
This command gives a path to the script - but there is a spaces at path and script can't find this file - how to deal with it?
The % operator in variable expansion removes the matching suffix pattern given to it. So ${0%/*} takes the variable $0, and removes all matching /* at the end. This is equivalent to the command dirname, which, when given a path, returns the parent directory of that path.
In order to deal with spaces in bash variable, whenever expanding the variable (i.e. whenever you write $var), you should quote it. In short, always use "$var" instead of just $var.
Consider reading shell parameter expansion and variable quoting in the bash manual to learn more about these two subjects.
strips the suffix matching /*, i.e. everything after last slash including the slash itself.
quote it wherever you use it (cat "$propFile").