Bash: how to avoid a command inside an alias being used as another alias?
Linux - NewbieThis Linux forum is for members that are new to Linux.
Just starting out and have a question?
If it is not in the man pages or the how-to's this is the place!
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
Bash: how to avoid a command inside an alias being used as another alias?
My shell is bash. I use several aliases for many things, I like them. Sometimes, when I need to run the "raw" command, I use single quotes in its name. Compare:
Code:
$ alias ls='ls -sh --color=auto'
$ ls # my normal ls
total 4,0M
20K aaa.txt
20K aab.txt
20K aac.txt
$ 'ls' # raw/real command
aaa.txt
aab.txt
aa3.txt
$ # Now I did a command to count number of files:
$ 'ls' | wc -l # it needs single quotes to avoid my alias
3
$
I want to make that command as an alias. I tried escaping the quotes, also with double quotes to limit the alias, ... the result was either: wrong count (would be 4 in the above example) due my normal ls being used; or an error saying that 'ls' (quotes included in the name!) does not exist.
How to avoid a command inside an alias being used as another alias? I want it to be the same it is when I single quote it in the command line.
You're escaping the command, it works for all commands AFAIK.
I found it strange to have not read about that before. I read parts of bash manual frequently. I did read bash manpage now, imagining it would say something about escaping commands. It does not! I have read all parts of it that contain the "escap" word. Where is that written?
Aliases allow a string to be substituted for a word when it is used as the first word of a simple command. The shell maintains a list of aliases that may be set and unset with the alias and unalias builtin commands (see SHELL BUILTIN COMMANDS below). The first word of each simple command, if unquoted, is checked to see if it has an alias.
The backslash quotes the first character of the command, preventing the alias expansion.
But "The backslash quotes...": that is not even close obvious to me.
That is what the backslash character does. It quotes the character that follows it. It's commonly used to quote characters like asterisk that would otherwise be special to the shell, but applies also to any other character that might, under some conditions such as an alias expansion, be treated specially.
That is what the backslash character does. It quotes the character that follows it. It's commonly used to quote characters like asterisk that would otherwise be special to the shell, but applies also to any other character that might, under some conditions such as an alias expansion, be treated specially.
I never, in my whole life, have seen anyone calling that "quoting". And I have been in IT area since many years ago. The idea of escaping (the IT jargon I know, and have for a long time too) is not even close to be applied to backslashes (I would call it "backslash escaping", but I decided to use a shorter option here).
You have inspired me to do a few more tests in my terminal. Read them thinking about 3 ways to "quote" things: backslah, single, double quotes, backslash inside quotes. Look:
Code:
$ touch 1asd\ lkj '2asd lkj' "3asd lkj"; alias ll='ls -l'; ll
1asd lkj
2asd lkj
3asd lkj
$ touch 4asda\nlkj '5asda\nlkj' "6asda\nlkj"; ll
1asd lkj
2asd lkj
3asd lkj
4asdanlkj
5asda\nlkj
6asda\nlkj
$ touch 7asdb*lkj '8asdb*lkj' "9asd*lkj"; ll
1asd lkj
2asd lkj
3asd lkj
4asdanlkj
5asda\nlkj
6asda\nlkj
7asdb*lkj
8asdb*lkj
9asd*lkj
$ # There was one extra "9" file in my tests, it is a mistake I did
$ # But it made me discover a new question! So I keep it here.
$ # Continue reading... the next command is *not* repeated!
$ touch 7asdb*lkj '8asdb*lkj' "9asdb*lkj"; ll # 9 with b
1asd lkj
2asd lkj
3asd lkj
4asdanlkj
5asda\nlkj
6asda\nlkj
7asdb*lkj
8asdb*lkj
9asdb*lkj
9asd*lkj
$ rm 9asd*lkj # this argument, without "b" and "\", pressing TAB after "J",
$ # expands to 9asdb\*lkj ! It should not!
$ # Why? It had two possibilities, it *chose* the first!
removido '9asd*lkj'
$ ll
1asd lkj
2asd lkj
3asd lkj
4asdanlkj
5asda\nlkj
6asda\nlkj
7asdb*lkj
8asdb*lkj
9asdb*lkj
$ touch 10*asd*; ll # does not touch any existing, but creates one file!
1asd lkj
2asd lkj
3asd lkj
4asdanlkj
5asda\nlkj
6asda\nlkj
7asdb*lkj
8asdb*lkj
9asdb*lkj
10*asd*
$ # We could expect no arguments should exist in this expression
$ # The reason I did it was just to test "almost equal" things.
$ # Look bvious, but...
$ # change prompt to have clock with seconds
12:31:00 [ this is PS1 now]
$ touch *asd*; ll
dez 10 12:31 10*asd*
dez 10 12:31 1asd lkj
dez 10 12:31 2asd lkj
dez 10 12:31 3asd lkj
dez 10 12:31 4asdanlkj
dez 10 12:31 5asda\nlkj
dez 10 12:31 6asda\nlkj
dez 10 12:31 7asdb*lkj
dez 10 12:31 8asdb*lkj
dez 10 12:31 9asdb*lkj
12:31:37 [ this is PS1 now]
$ touch '*asd*'; ll # only after 12:32:00!
$ # it did not touch, just created one file
dez 10 12:31 10*asd*
dez 10 12:31 1asd lkj
dez 10 12:31 2asd lkj
dez 10 12:31 3asd lkj
dez 10 12:31 4asdanlkj
dez 10 12:31 5asda\nlkj
dez 10 12:31 6asda\nlkj
dez 10 12:31 7asdb*lkj
dez 10 12:31 8asdb*lkj
dez 10 12:31 9asdb*lkj
dez 10 12:32 *asd*
12:32:57 [ this is PS1 now]
$ touch "*asd*"; ll # only after 12:33:00!
$ # it did not create a file, just touched the most recent
dez 10 12:31 10*asd*
dez 10 12:31 1asd lkj
dez 10 12:31 2asd lkj
dez 10 12:31 3asd lkj
dez 10 12:31 4asdanlkj
dez 10 12:31 5asda\nlkj
dez 10 12:31 6asda\nlkj
dez 10 12:31 7asdb*lkj
dez 10 12:31 8asdb*lkj
dez 10 12:31 9asdb*lkj
dez 10 12:33 *asd*
12:33:40 [ this is PS1 now]
$
I will make a *separate* post for the question I discovered in these tests. Please wait, if you want to answer it. I will be easier to quote, and I am doing it now.
It gets very messy, especially with all the special cases of backslash within double quotes. And, tab completion does not respect wildcards -- all the preceding characters in the word are taken literally.
Do not miss my previous post. It is important. This one is just for a new question, in the title, that also makes the thread to be unsolved, not a new thread - seemed better.
The following situation happens in a Debian 9 using with bash shell. Look at these commands:
Code:
$ touch "9asd*lkj"; ll
9asd*lkj
$ touch "9asda*lkj"; ll
9asda*lkj
9asd*lkj
$ # Before pressing enter for the next command, I tried to expand the argument.
$ rm 9asd*lkj
The argument to rm, as shown, is expanded to one of the two choices it had! It expands to "9asda\*lkj" - without the quotes, plus a space that possibly expected an argument. We normally conclude that the *only* possible file was found, then - at least me. Wouldn't you?
Do you consider this a bug in Bash? I do, but I would like to see more opinions in this.
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.