LinuxQuestions.org
Register a domain and help support LQ
Go Back   LinuxQuestions.org > Forums > Linux Forums > Linux - Newbie
User Name
Password
Linux - Newbie This 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


Reply
  Search this Thread
Old 01-16-2013, 06:50 AM   #1
TheBigMing
Member
 
Registered: Dec 2008
Location: east anglia
Distribution: SuSE, antiX
Posts: 36

Rep: Reputation: 7
Arrow Using variables in aliases - some things not fully understood


I keep a folder of scripts & aliases which I've compiled over 12 years or so and which I load into each install. I don't often look at them, they all work, some may be a bit outdated but, I'm used to them, that's OK by me. Lately, however, I've been tidying up a bit, and have realised there is something I understand (sort of) but do not understand why it is so.

The anomaly is with passing variables to aliases. It seems that it is possible to pass one variable to an alias but not two (except in certain circumsances - see Example4 below) and the variable passed has to be the last item in the alias.

Here is an example of an alias to which a variable is passed successfully and which behaves as expected (but NB the use of single - not double - quotes which, I guess, protects the variable from expansion somewhere in transit. Anyway, it doesn't work with double quotes - see also Example4 below):

Example1:
Code:
	alias FaF="find / \! -type d 2>> /dev/null | grep -Ei "$1""
	$ FaF '/vim$|/vi$'			# Calling line - single quotes
	/usr/share/doc/vim			# The output
	/usr/share/lintian/overrides/vim
	/usr/bin/vi
	/usr/bin/vim
	/var/lib/dpkg/alternatives/vi
	/var/lib/dpkg/alternatives/vim
	/etc/alternatives/vi
	/etc/alternatives/vim
and here is one which doesn't:

Example2:
Code:
	dmk-antiX@antiXdell:~
	$ alias XWStst="grep -Ei "^$1$" /usr/share/dict/words"
	dmk-antiX@antiXdell:~
	$  XWStst "....o.r...i.n"	# Calling line
	/usr/share/dict/words:Acan be	# Some of the output	
	/usr/share/dict/words:A'asia	
	/usr/share/dict/words:A's	# grep is reading
	/usr/share/dict/words:AA	# /usr/share/dict/words
	/usr/share/dict/words:AA's	# from A to Z.
But this last one can be made to work by passing the variable to a script:

Example3:
Code:
	dmk-antiX@antiXdell:~
	$ cat XWS.sh
	grep -Ei "^$1$" /usr/share/dict/words	# The shell script
	dmk-antiX@antiXdell:~
	$ alias XWStst="bash XWS.sh "$1""	# The alias
	dmk-antiX@antiXdell:~
	$ XWStst "....o.r...i.n"		# Calling line
	appropriation				# The output - as it should be
	expropriation
	impropriation
	introgression
	miscorrection
	retrogression
And, finally, the last example (using an alias to pass a variable) seems to be the only way of using multiple variables in an alias. This next example shows variables being entered & passed in a fairly randomised manner, but being kept track of and arriving at the end, safely, in the correct order:

REGRETTABLY. I HAVE TO CONFESS THAT EXAMPLE 4 IS RUBBISH - I COULD HAVE SWORN THAT I HAD GOT IT WORKING BUT, AFTER SEEING SUICIDALEGGROLL'S POST (BELOW), I WENT BACK TO CHECK IT. THE VARIABLES DO GET PASSED TO THE SHELL SCRIPY BUT ONLY IN THE WAY DEMONSTRATED IN EXAMPLE 5. I APOLOGISE BUT LEAVE THIS IN AS AN EXAMPLE OF SOMETHING THAT DOESN'T WORK!


Code:
			$1	$2	$3
	==>choTst	of	bucket	blood
	choTst==>	blood	bucket	of
	chotst.sh==>	bucket	of	blood
Example4:
Code:
	dmk-antiX@antiXdell:~
	$ alias choTst='bash chotst.sh $3 $2 $1'	# NB single quote(')
	dmk-antiX@antiXdell:~
	$ cat chotst.sh
	echo $2 $3 $1					# The shell script
	dmk-antiX@antiXdell:~
	$ choTst of blood bucket			# Calling line
	bucket of blood					# The output
But, of course, passing multiple variables through to a script is one thing. Getting them out of an alias is something else:

Example5:
Code:
	dmk-antiX@antiXdell:~
	$ alias choTst="echo $3 $2 $1"		# The alias
	dmk-antiX@antiXdell:~
	$ choTst of bucket blood		# Calling line
	of bucket blood
The variables $3, $2, $1 are ignored - not expanded - the alias simply operates as the command "echo of blood bucket". I have tried pretty much every combination of single, double or no quotes and/or escapes available with various differing results - none of them what I wanted.

All of which is interesting - and I have stuff written before the end of the last millenium which recognizes this - but, although I have searched, I cannot find an explanation of why it is so. Any ideas?

Last edited by TheBigMing; 01-19-2013 at 12:19 PM. Reason: Error
 
Old 01-16-2013, 08:32 AM   #2
bijo505
Member
 
Registered: Nov 2012
Location: Bangalore
Distribution: Fedora & Ubuntu
Posts: 77

Rep: Reputation: 18
Quote:
Originally Posted by TheBigMing View Post

Example2:
Code:
	dmk-antiX@antiXdell:~
	$ alias XWStst="grep -Ei "^$1$" /usr/share/dict/words"
	dmk-antiX@antiXdell:~
	$  XWStst "....o.r...i.n"	# Calling line
	/usr/share/dict/words:Acan be	# Some of the output	
	/usr/share/dict/words:A'asia	
	/usr/share/dict/words:A's	# grep is reading
	/usr/share/dict/words:AA	# /usr/share/dict/words
	/usr/share/dict/words:AA's	# from A to Z.
The variables $3, $2, $1 are ignored - not expanded - the alias simply operates as the command "echo of blood bucket". I have tried pretty much every combination of single, double or no quotes and/or escapes available with various differing results - none of them what I wanted.

All of which is interesting - and I have stuff written before the end of the last millenium which recognizes this - but, although I have searched, I cannot find an explanation of why it is so. Any ideas?

Hi TheBigMing,

Alias will echo the content as it is on the shell. It will not replace variable with the argument.

from the man bash
Code:
Aliases are created and listed with the alias command, and removed with the unalias command.
There is no mechanism for using arguments in the replacement text.  If arguments are needed, a shell function should be used
I hope it will clear your doubts.

Last edited by bijo505; 01-17-2013 at 02:24 AM.
 
Old 01-16-2013, 11:46 AM   #3
jpollard
Senior Member
 
Registered: Dec 2012
Location: Washington DC area
Distribution: Fedora, CentOS, Slackware
Posts: 4,655

Rep: Reputation: 1256Reputation: 1256Reputation: 1256Reputation: 1256Reputation: 1256Reputation: 1256Reputation: 1256Reputation: 1256Reputation: 1256
I think your quotes on the alias are wrong-

Code:
alias XWStst="bash XWS.sh "$1""
The quoting actually does:

alias XWStst=bash XWS.sh $1

Which would perform the substitution at the time the alias is created. You might try

Code:
alias XWStst='bash XWS.sh "$1"'
Which would suppress the evaluation of the $1 until the alias is actually used.
 
Old 01-17-2013, 11:54 AM   #4
TheBigMing
Member
 
Registered: Dec 2008
Location: east anglia
Distribution: SuSE, antiX
Posts: 36

Original Poster
Rep: Reputation: 7
@bijou505 - Thanks for your reply. I hadn't seen that part of the bash manual but I'm not sure that it answers my query.

Of the code you use from Example2, the relevant part is:

Code:
grep -Ei "^$1$" /usr/share/dict/words
grep is supposed to search the contents of the file
Code:
/usr/share/dict/words
for the pattern
Code:
"....o.r...i.n"
The pattern is passed by $1.

What is happening is that $1 is being "ignored" and the output is what we would get from
Code:
grep -Ei /usr/share/dict/words
but if we pass this through a shell script the output is what we are looking for.

However, example1, where $1 the variable/argument is at the end of the line, works perfectly.

in Example4 and example5 the problem is the manipuation of variables. Why do the variables/arguments passed from an alias behave correctly when passed to a shell script but not as an alias? Why does

Code:
dmk-antiX@antiXdell:~
$ alias choTst='bash chotst.sh $3 $2 $1'
produce "blood bucket of" while

Code:
$ alias choTst="echo $3 $2 $1"
merely reproduces the arguments ($1, $2, $3) in the order they were entered "of bucket blood"?


@ipollard - Thanks for your input. Sometimes it is crucial that you use either single or double quotes but often Linux takes a "Frankly my dear, I don't give a damn!" view. In this case, here are things that work & things that don't work:

Code:
Things that work:
$ alias XWStst="bash ~/XWStst.sh "$1""	# doubles all round
$ alias XWStst="bash ~/XWStst.sh $1"	# 2 doubles only
$ alias XWStst='bash ~/XWStst.sh $1'	# 2 singles only
$ alias XWStst='bash ~/XWStst.sh '$1''	# singles all round

and things that don't:
$ alias XWStst="bash ~/XWStst.sh '$1'"	# 2 doubles, 2 singles
$ alias XWStst='bash ~/XWStst.sh "$1"'	# as above reversed
===================================

Actually, of course, this all slightly inconsequential. I've learned enough to be able to do what I want to and, anyway, even if I hadn't, it would be easy enough (even easier perhaps) to create a folder full of shell scripts and put it on my path.

This post was really just for interest's sake - a quest for theoretical rather than purely practical knowledge.

Last edited by TheBigMing; 01-17-2013 at 12:09 PM.
 
Old 01-17-2013, 07:13 PM   #5
suicidaleggroll
LQ Guru
 
Registered: Nov 2010
Location: Colorado
Distribution: OpenSUSE, CentOS
Posts: 5,365

Rep: Reputation: 2004Reputation: 2004Reputation: 2004Reputation: 2004Reputation: 2004Reputation: 2004Reputation: 2004Reputation: 2004Reputation: 2004Reputation: 2004Reputation: 2004
Quote:
Originally Posted by TheBigMing View Post
@bijou505 - Thanks for your reply. I hadn't seen that part of the bash manual but I'm not sure that it answers my query.

Of the code you use from Example2, the relevant part is:

Code:
grep -Ei "^$1$" /usr/share/dict/words
grep is supposed to search the contents of the file
Code:
/usr/share/dict/words
for the pattern
Code:
"....o.r...i.n"
The pattern is passed by $1.

What is happening is that $1 is being "ignored" and the output is what we would get from
Code:
grep -Ei /usr/share/dict/words
but if we pass this through a shell script the output is what we are looking for.

However, example1, where $1 the variable/argument is at the end of the line, works perfectly.

in Example4 and example5 the problem is the manipuation of variables. Why do the variables/arguments passed from an alias behave correctly when passed to a shell script but not as an alias? Why does

Code:
dmk-antiX@antiXdell:~
$ alias choTst='bash chotst.sh $3 $2 $1'
produce "blood bucket of" while

Code:
$ alias choTst="echo $3 $2 $1"
merely reproduces the arguments ($1, $2, $3) in the order they were entered "of bucket blood"?
Yes, this is because there is no argument handling in aliases. None whatsoever. Your $1, $2, $3, or whatever else you want to put there are just being expanded to nothing, all the time. An alias is NOT a function that takes input arguments and does something with them. An alias is just telling the shell, "When I type this, what I really mean is that". You can think of it as a string replacement, that's it.

Example1:
Code:
$ alias FaF="find / \! -type d 2>> /dev/null | grep -Ei "$1""
$ FaF '/vim$|/vi$'
is being expanded to
$ find / \! -type d 2>> /dev/null | grep -Ei "" '/vim$|/vi$'
When you type "FaF", it is being replaced by the literal string "find / \! -type d 2>> /dev/null | grep -Ei """. Then anything you write on the command line after "FaF" is stuck on the end.


Example2:
Code:
$ alias XWStst="grep -Ei "^$1$" /usr/share/dict/words"
$ XWStst "....o.r...i.n"
is being expanded to
$ grep -Ei "^$" /usr/share/dict/words "....o.r...i.n"


Example5:
Code:
$ alias choTst="echo $3 $2 $1"
$ choTst of bucket blood
is being expanded to
$ echo    of bucket blood
An alias is just a string replacement, not a function. You don't "pass" it anything.

Last edited by suicidaleggroll; 01-17-2013 at 07:17 PM.
 
2 members found this post helpful.
Old 01-18-2013, 11:48 AM   #6
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Debian sid + kde 3.5 & 4.4
Posts: 6,823

Rep: Reputation: 1958Reputation: 1958Reputation: 1958Reputation: 1958Reputation: 1958Reputation: 1958Reputation: 1958Reputation: 1958Reputation: 1958Reputation: 1958Reputation: 1958
As stated, an alias is just a simple text substitution. If the first word of the command matches an alias entry, then it is replaced with the alias substitution text.

Code:
#if you have this alias:
alias foo='sub text'

#and you run this command:
foo arg1 arg2

#this is what the shell actually runs:
sub text arg1 arg2
That's all it does. There is no reorganization of the line, or insertion of text, just a simple "foo"-->"sub text" replacement. Of course this can lead to some interesting and complex commands in the hands of a creative person, but in the end there's a hard limit to what they can do.

Now, when you use a variable in an alias, what happens depends on how you quote the string.

If you soft quote it, then the variable is expanded as the alias is set, and the result is an alias with a fixed string. Since aliases are usually set at start-up, when your bashrc or whatever is parsed, chances are it will result in a blank space, unless the variable was also previously defined in the startup script.


If you hard-quote the alias definition, then the variable does not expand when the alias is set, it just sits there in the string as-is, and only expands when the alias is used. So the content will be whatever that variable is set to when the command is run.


For true flexibility you have to use functions, which allow you to parse the entire line at will.
 
1 members found this post helpful.
Old 01-18-2013, 06:46 PM   #7
TheBigMing
Member
 
Registered: Dec 2008
Location: east anglia
Distribution: SuSE, antiX
Posts: 36

Original Poster
Rep: Reputation: 7
Arrow

Aha! This is more like it.

Quote:
"I keep a folder of scripts & aliases which I've compiled over 12 years or so and which I load into each install. I don't often look at them, they all work, some may be a bit outdated but, I'm used to them, that's OK by me. Lately, however, I've been tidying up a bit, and have realised there is something I understand (sort of) but do not understand why it is so."
--- and now I understand!


Quote:
When you type "FaF", it is being replaced by the literal string

`"find / \! -type d 2>> /dev/null | grep -Ei """.

Then anything you write on the command line after "FaF" is stuck on the end.
which, I guess, was the point Bijou was making. And:

Quote:
If you soft quote it, then the variable is expanded as the alias is set, and the result is an alias with a fixed string. Since aliases are usually set at start-up, when your bashrc or whatever is parsed, chances are it will result in a blank space, unless the variable was also previously defined in the startup script.
So, this is hardly useful but it does show what can be done:

Code:
dmk-antiX@antiXdell:~
$ alias ChoTst="TESTVAR='My Little Pony';echo -e $TESTVAR $1;echo Your Path is set to this"
dmk-antiX@antiXdell:~
$ ChoTst rubbish
My Little Pony
Your Path is set to this rubbish
which is not something I knew about!

There is one thing, however, that slightly confuses me:

Quote:
If you hard-quote the alias definition, then the variable does not expand when the alias is set, it just sits there in the string as-is, and only expands when the alias is used. So the content will be whatever that variable is set to when the command is run.
This surely is not entirely true? The system recognises the variable as an object but will only deal with it after the alias - not as part of the alias. The whole point of all this is that the variable is not expanded until after the alias. In fact, as noted in my reply to ipollard (see posts above), the hard coded variables are the only ones that don't work and, further to that, the use of input variables in aliases seems wholly redundant. Take the alias:

Code:
FaF="find / \! -type d 2>> /dev/null | grep -Ei "$1""
either of these will perform exactly the same job:

Code:
$ alias FaFtst="find / \! -type d 2>> /dev/null | grep -Ei"	# No variable
or
$ alias FaFtst="$1 find / \! -type d 2>> /dev/null | grep -Ei"	# Variable first
and this is something else I've only just worked out!

As I have said, a lot of this I knew but didn't know - if that makes sense - and I now know. Also, I hunted around the net looking for something which explained all this without finding anything. If anyone else wants to look at either aliases or variables, I think this is a good resource.

I would also recommend David the H's contribution here:

http://www.linuxquestions.org/questi...sh-4175445682/

(I have to re-read it more closely, but, you may be hearing from me again!)

Thanks for the interest.

dmk

Last edited by TheBigMing; 01-19-2013 at 12:20 PM. Reason: extra matter
 
Old 01-20-2013, 02:34 PM   #8
David the H.
Bash Guru
 
Registered: Jun 2004
Location: Osaka, Japan
Distribution: Debian sid + kde 3.5 & 4.4
Posts: 6,823

Rep: Reputation: 1958Reputation: 1958Reputation: 1958Reputation: 1958Reputation: 1958Reputation: 1958Reputation: 1958Reputation: 1958Reputation: 1958Reputation: 1958Reputation: 1958
Quote:
Originally Posted by TheBigMing View Post
The whole point of all this is that the variable is not expanded until after the alias.
That's correct. Perhaps I could've worded it better. When the alias substitution is done (using a hard-quoted alias), the raw variable name will be inserted into the line. Then the shell parses the resulting command as usual and expands the variable into whatever value it has in the current environment.


As for the two aliases you posted, it's no wonder that they perform the same. Remember again that aliases are NOT functions, and they don't have input parameters. Any numbered parameters you use in them will be those of the main shell process, and interactive shells generally won't have any of those (unless you manually create some with the set command).

So they do the same job because there is no "$1" set in your shell, and they end up expanding to essentially the same command.

And of course in the one place where you will have numbered parameters, scripts, it's rather pointless to use aliases.


User-set variables do have some use in aliases though, such as setting common options that will be used by multiple aliases. I have these in my bashrc, for example:

Code:
qmvopts=( '-v' '-f' 'sc' '-o' "separate,indicator1='f|',indicator2='t|'" )
alias qmv="qmv ${qmvopts[@]}"
alias qcp="qcp ${qmvopts[@]}"
qmv/qcp are part of the renameutils.



As for your find command, the only way to get it to work exactly as you want, so that the argument word gets inserted into the middle of a grep regex, is with a function:

Code:
FaF() {
    find / ! -type d 2>/dev/null | grep -Ei "^$1$"
}
Although you'd really be better off using find the way it's intended:

Code:
FaF() {
    find / ! -type d -iregex "$1" -print 2>/dev/null
}
Here are a couple of good links about using find:
http://mywiki.wooledge.org/UsingFind
http://www.grymoire.com/Unix/Find.html
 
1 members found this post helpful.
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
-jar not understood? Squerl101 Linux - Server 2 11-04-2011 03:17 PM
ProFTP ... 500 Auth not understood dancindoc Linux - Networking 3 04-07-2010 06:09 AM
Message in Konsole not understood Patrick-Warwick Linux - Desktop 3 01-09-2009 10:31 AM
wrap lines at 80 for long aliases in .aliases.csh jhwilliams Linux - Software 0 07-26-2007 08:49 AM
argument variables in .bashrc's aliases? stabu Slackware 3 12-15-2006 12:30 PM


All times are GMT -5. The time now is 10:05 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration