1

Is there a way to display aliases after bash has made the substitutions?

Background:
I have a long alias that performs actions on a directory.

alias do_it='cd my_working_dir; do_stuff'

This works fine, but the alias is quite long and my_working_dir changes often. Rather than do a in-depth search on my alias for all occurrences of my_working_dir, I changed to this:

MY_WORKING_DIR=some_dir
alias do_it='cd ${MY_WORKING_DIR}; do_stuff'

This works fine.

However, sometimes I want to make slight changes to the alias on the fly. With the previous alias construction, I was able to type alias, copy/paste the command I wanted, make mods and execute. Using this substitution, when I type alias I get:

do_it='cd ${MY_WORKING_DIR}; do_stuff'

Now I have to manually replace MY_WORKING_DIR. Is there a handy way to get a copy of the alias after bash has made the substitutions (in this case the substitution for ${MY_WORKING_DIR}.

Clarification: My goal is not change the inputs to the alias/function. I wish to display the resulting alias/function with substitutions already made so that I can copy/paste that output to make more complex commands. I have yet to find a way to display either aliases or functions with the substitutions already made.

Additional Example

TARGET_DIR='my_dir'    
alias do_it='cd ${TARGET_DIR}; run task; echo "Task done in ${TARGET_DIR}'
alias
do_it='cd ${TARGET_DIR}; run task; echo "Task done in ${TARGET_DIR}'

If I want to repeat the alias 50x, I could copy the alias output, then paste it into the following line:

for i in {1..50}; do <paste_here>; done

But that won't work because the alias output has left ${TARGET_DIR} unresolved.

Using a function instead of an alias does not work either because declare likewise does not replace ${TARGET_DIR}.

This is a simplified example. The real aliases I am using are long and tedious, with ${TARGET_DIR} occurring many times, so while the alias/function works great, composing the alias output into more complex on-the-fly commands requires me to manually replace ${TARGET_DIR} multiple times.

5
  • Is there a reason you don't make this a shell function instead, with the directory as an argument (possibly with a default value)?
    – Kusalananda
    Commented Feb 17, 2023 at 18:33
  • The only reason would be aliases are easier to implement. Thanks for the suggestion. I'll try using a function instead.
    – JS.
    Commented Feb 17, 2023 at 18:35
  • I still don't understand what it is you want to do. Sorry.
    – Kusalananda
    Commented Feb 17, 2023 at 19:21
  • In your "Additional Example", you want to run the alias 50 times, each time with another TARGET_DIR value? That's literally what turning it into a function that takes the directory as an argument would allow you to do (see the end of my answer below). In fact, since the alias uses $TARGET_DIR unresolved, just changing this variable's value and calling the alias again would probably also work, although using a function would allow you to handle quoting better.
    – Kusalananda
    Commented Feb 17, 2023 at 19:37
  • No, $TARGET_DIR is just the repository I'm working out of at the time. It changes every few days or so. The directory name is a hash of the git branch name. The whole point is to avoid typing in the long directory name each time. I want to change it in the .bashrc every once in a while and have all my aliases working and copy/pastable on the fly. Displaying functions doesn't resolve substitutions any better than displaying aliases.
    – JS.
    Commented Feb 17, 2023 at 21:08

3 Answers 3

0

Not really that I know, at least not in a safe and generic way. That also seems like an extremely strange way of using aliases to me.

Are you sure a shell script wouldn't be more appropriate? Something placed on your $PATH (adjust $PATH if needed) and named do_it, that may take arguments.

You could also have that script do the same actions as your alias, and display the alias command with substitutions if asked.


If you insist on aliases, this is exremely unsafe as you risk expanding more than you want, mishandle escape characters like \, etc, but you could do something similar to:

$ alias test='echo $UID'
$ alias xalias='f(){ eval echo $(echo $(alias "$@" | sed s,\'\'',\'\\\\\\\\\\\\\'',g ) ) ; unset -f f; }; f'
$ xalias test
alias test='echo 1000'

Getting the quotations right was an exercise in frustration. This works by quoting the single quotes: ' -> \', then quoting all of that again. The first eval call unquotes a level, and at that point, the ${VAR} are not quoted, so they are evaluated. Then echo adds back the quotation marks, as the string is evaluated in a subshell. I may have overcomplexified a bit due to the number of indirections.

That's still quite brittle, and bash+sed is a bad fit for this job.

0

Since it appears you want to change the working directory every once in a while, a suggestion would be to replace the alias with a shell function, which could take the directory pathname as a command line argument:

do_it () {
    local wd="${1:-my_working_dir}"
    cd "$wd" || return
    do_stuff
 }

This function takes an optional single argument, a directory pathname. If given, the function's local wd variable is set to this value. If not given, the local wd variable is set to the static string my_working_dir.

With a small change, you could disallow the function from leaving the user in an unexpected working directory:

do_it () {
    local wd="${1:-my_working_dir}"
    (
        cd "$wd" || return
        do_stuff
    )
 }

The parenthesised subshell's environment inside the function (which includes the current working directory, possibly modified by cd) would not affect the environment of the calling shell.

You would declare this function wherever you usually declare aliases, and you would use it either as

do_it

or with an argument,

do_it some/directory/path

or, in a loop that runs it over a number of directory pathnames,

for target_dir in some/pattern/dir*/
do
    do_it "$target_dir"
done
4
  • How would I display the resulting commands so that I could cut and paste them into new commands?
    – JS.
    Commented Feb 17, 2023 at 19:11
  • @JS. I'm not quite sure I understand. Why would you want to do that? According to the question, the only thing you wanted to change was to use another directory.
    – Kusalananda
    Commented Feb 17, 2023 at 19:12
  • @JS. It's quite possible that I've misunderstood what it is you want to accomplish. It would be good if you could clarify this in your question by showing more in-depth examples.
    – Kusalananda
    Commented Feb 17, 2023 at 19:14
  • @JS. That sounds like an XY problem. Please ask about your problem or what you are trying to accomplish instead.
    – MayeulC
    Commented Feb 19, 2023 at 17:55
0

This is a duplicate of:

how to expand aliases inline in bash?

and

Expand subshell before executing it?

Turns out, BASH uses readline to handle this. Just press Esc followed by Ctrl-e

To test, I have the following alias defined in my .bash_profile:

alias cdh='cd ${HOME}'

Starting a new shell/terminal allows me to type:

cdh

Then press: Esc Ctrl-e

and readline updates the command-line to:

cd /home/user_name 

MacOS 13.2.1
iterm2 3.4.15
bash 5.1.8(1)-release (x86_64-apple-darwin21.2.0)

Ubuntu 20.04.5 LTS
5.0.17(1)-release (x86_64-pc-linux-gnu)

You must log in to answer this question.

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