0

I have 3 aliases. They are named echo1, echo2, echo3

How do i execute all 3 of them as part of a larger command?

$ alias echo1='echo 1'
$ alias echo2='echo 2'
$ alias echo3='echo 3'

$ echo1
1

$ echo2
2

$ echo3
3

$ echo{1..3}
bash: echo1: command not found

$ bash -ic echo{1..3}
echo2: echo1: command not found

$ bash -ic 'echo{1..3}'
bash: echo1: command not found

Solution: based on Kusalananda's answer:

 printf '%s\n' {1..3} | xargs -I {} bash -ic "echo{}"
yosefrow
  • 389
  • 1
    There's an interesting question buried here somewhere, but I can't figure out what you thought that command would do. – Wildcard Jun 01 '17 at 00:57
  • I rephrased the question – yosefrow Jun 01 '17 at 01:01
  • 1
    What do your aliases do? There is no situation in which this command could possibly work. At the most, you would run one alias with the names of the other two aliases passed as arguments. But it looks like your aliases aren't even defined in the shell you're spawning. – Wildcard Jun 01 '17 at 01:09
  • they are definitely defined and sourced – yosefrow Jun 01 '17 at 01:26
  • rewrote the question again using a different simpler example – yosefrow Jun 01 '17 at 01:29
  • Even if you ran echo1 echo2 echo3 it would not accomplish what you intend, though. – Wildcard Jun 01 '17 at 01:32
  • @Wildcard I tried bash -ic before and it still didnt work. thats whats making me so confused. -i is supposed to call interactive mode – yosefrow Jun 01 '17 at 01:33
  • 1
    It appears that alias expansion is performed before brace expansion. This doesn't surprise me, but I don't see it mentioned in man bash, which does surprise me. However, aliases defined in the current shell aren't inherited by child shells, so I wouldn't expect bash -ic aliasname to work regardless of brace expansion. – Wildcard Jun 01 '17 at 01:34
  • @Wildcard yeah this is my assumption as well. I was wondering if there was some workaround – yosefrow Jun 01 '17 at 01:38
  • 1
    As I noted before, alias1 alias2 alias3 would only ever run one alias. So why would you want alias{1..3} to do that anyway? Just run alias1;alias2;alias3. If you want to run multiple aliases with the same arguments, you shouldn't be using aliases; you should be using a single function which encompasses the purposes of all three aliases. See https://unix.stackexchange.com/q/30925/135943 – Wildcard Jun 01 '17 at 01:43
  • You are right. There is no real reason to get this to work. – yosefrow Jun 01 '17 at 03:26
  • The solution to my real problem is a for loop with eval. – yosefrow Jun 01 '17 at 03:27
  • eval is a problem, not a solution. ;) At least 99.9% of the time there is a better solution than eval. I doubt you've hit the 0.1% here. – Wildcard Jun 01 '17 at 03:51
  • I was thinking to run a for loop and refer to the iterator $i

    ie. command$i some-parameter

    – yosefrow Jun 01 '17 at 04:18

4 Answers4

3

Because of the order of evaluation of things, echo$i would be evaluated to the string echo1 (for i=1) after alias expansion.

To be able to make use of the string as an alias, you need to re-evaluate the resulting string:

for i in 1 2 3; do
    eval "echo$i"
done

If echo1, echo2 and echo3 had been shell functions, then the eval had not been needed (tested in Bash 4.4).

Your attempts with bash -c will not work as the aliases are local to the current shell session.

Your initial thing

echo{1..3}

would result in

echo1 echo2 echo3

Even if echo1 had been expanded to echo 1, the result had been the output of the string

1 echo2 echo3

Personally, depending on what you'd wanted the aliases to actually do, I would have implemented a function:

dothing () {
    printf '%s\n' "$@"
}

... and then called that with

dothing {1..3}

to produce

1
2
3

Of course, that would have been achieved with printf '%s\n' {1..3} directly...

Kusalananda
  • 333,661
  • using the -i flag introduces interactive mode which does simulate a manually opened shell with sourced ~/.bashrc ~/.bash_aliases etc.

    So bash -ci technically should work. but its irrelevant in this case because even if it did work yould end up with echo1 echo2 echo3 which would pass echo2 and echo3 as parameters to echo1

    – yosefrow Jun 01 '17 at 05:52
  • @yosefrow It still would not allow you to call an alias with echo$i. – Kusalananda Jun 01 '17 at 05:55
  • ok i tested this just now bash -ic works fine as long as the alias is define in ~/.bash_aliases and sourced in ~/.bashrc – yosefrow Jun 01 '17 at 05:58
  • It follows that if i used eval, i could definitely call echo$i. but a for loop makes the most sense i think – yosefrow Jun 01 '17 at 06:00
  • You just gave me a great idea!

    printf '%s\n' {1..3} | xargs -I {} bash -ci "echo{}"

    – yosefrow Jun 04 '17 at 03:03
  • Even though my own solution achieves what i want I marked yours as accepted, because without it I couldn't have done it – yosefrow Jun 04 '17 at 03:06
0

Why not making another function who execute the aliases?

function execute_all_aliases{
  alias1
  alias2
  alias3
}
0

You could always do:

eval echo{1..3}\;

That is tell the shell to evaluate the expansion of that as shell code, that is evaluate:

echo1; echo2; echo3;

Some other variants:

eval echo{1..3}$'\n' # separate with newline instead of ;. Can make a
                     # difference for things like alias echo1='echo x|'
                     # alias echo2='tr x y'

eval echo{1..3}'&&' : # only run the next one if the previous one succeeded
0

Thanks to @Kusalananda I came up with the following solution:

printf '%s\n' {1..3} | xargs -I {} bash -ic "echo{}"

This will achieve the goal of executing n amount of aliases named sequentially with other command parts

yosefrow
  • 389