Create an alias that takes a file name as a paremeter, removes the extension of the parameter and creates a new extension [duplicate]

Solution 1:

Aliases don't take arguments. With an alias like alias foo='bar $1', the $1 will be expanded by the shell to the shell's first argument (which is likely nothing) when the alias is run.

So: Use functions, instead.

d () {
  num=${1:-5}
  dmesg |grep -iw usb|tail -$num
}

num=${1:-5} uses the first argument, with a default value of 5 if it isn't provided.

Then you can do:

$ d
# prints 5 lines
$ d 10
# prints 10 lines

Or, if you change the options you used slightly:

alias d="dmesg|grep -iw usb|tail -n 5"

Then you can pass additional -n options:

$ d
# prints 5 lines
$ d -n 10
# prints 10 lines

If multiple -n options are specified for tail, only the last is used.

Solution 2:

You need to have a function for this as described in the SO and here. Try the following:

foo() { /path/to/command "$@" ;}

and call the foo with:

foo arg1 arg2 arg3

Solution 3:

Working around alias limitations with group command and here-string

Aliases can't take arguments, but we can "simulate" that. Take for instance example of my answer on this question.

alias mkcd='{ IFS= read -r d && mkdir "$d" && cd "$d"; } <<<'

Key points that are happening here:

  • we use read built in to read a string into a variable d. Because we want to read a full string including blank characters(newline's,tabs,spaces), we use IFS= and disable back backslash escapes with -r.
  • <<< which is here-string operator allows us to redirect whatever string we provide as argument to mkcd alias; the usage would be as mkcd "some directory"
  • multiple commands within alias are combined and executed in current shell using { list; } structure (which is known as group command in the bash manual). Note that leading space after { and ; individual list of commands are required.

In your specific example we could do:

alias d='{ IFS= read -r n; dmesg | grep -iw "usb" | tail -n ${n:-5};} <<<'

We could also make use of word splitting to store space-separated arguments:

bash-4.3$ { read -r a1 a2; echo "$a1"; echo "$a2";}  <<< "arg1 arg2"
arg1
arg2

Or we could use arrays to provide multiple arguments:

bash-4.3$ { read -a arr; echo "${arr[1]}"; echo "${arr[0]}";}  <<< "arg1 arg2"
arg2
arg1

But is this good approach ?

Not necessarily. The problem with such approach is that it's very specific - arguments can't be quoted easily which means we can only have arguments with no spaces.

bash-4.3$ { read -r a1 a2; echo "$a1"; echo "$a2";}  <<< "'arg1 with space' arg2"
'arg1
with space' arg2

This is of course not something that would be widely used, simply because in the real world we have to deal with complex arguments, so this approach isn't quite practical. Functions are far more flexible. And the need to quote args string becomes annoying fast.

Despite the limitations, this works with simple strings as arguments where we can afford word splitting, thus partially allows us to give arguments to aliases.