I have a few command that I would like to run faster. Best solution seems to be an alias (in fact, a function because I need to use avec few arguments). I would like my alias to be run when the system starts. So I've created a bash file to execute it. To create my function, I key this stuff in my shell :
function myFunction() { command 1 ; command 2 ; etc... }
But here is the problem ! My bash file do not execute the whole command because myFunction is reconized as... a function ! But an internal function.
So is there any way to make the file executing the whole function ?
Thanks a lot guys !
You could just define the function in your ~/.bashrc or from there, source the file in which it is defined.
Related
Background:
I'm trying make a function that runs commands on a set interval because I don't have access to a "watch" program. Simplified to it's most basic from, the function I'm trying to write is runit() { $1; }.
What works:
This works fine and dandy when I pass it things that aren't aliases. For example, runit "ls -l" works fine. I get the full output from the ls -l command.
What doesn't work:
The problem starts when I pass it an alias. For example, setting alias ll="ls -l" then calling runit "ll" will result in -bash: ll: command not found.
Things I have tried:
When I hard-code the alias runit() { ll; }, it works fine and gives me what I expect.
I feel like I might be overlooking something, but I can't quite place my finger on it.
Why would hard-coding the alias work fine, but passing it into the function fail?
Is there a way to accomplish what I'm attempting to do?
From the bash man page discussion of aliases (emphases mine):
Aliases are expanded when a command is read, not when it is executed.
Therefore, an
alias definition appearing on the same line as another command does not take effect until the next line of input is read. The
commands
following the alias definition on that line are not affected by the new alias. This behavior is also an issue when functions are
executed. Aliases are expanded when a function definition is read, not when the function is executed, because a function
definition is
itself a compound command. As a consequence, aliases defined in a function are not available until after that function is executed.
To
be safe, always put alias definitions on a separate line, and do not use alias in compound commands.
You can observe this effect in functions by using the type command:
$ run_it () { ll; }
$ type run_it
You should see that the body of the function contains a call to ls -l, not ll.
The last sentence of the section on aliases:
For almost every purpose, aliases are superseded by shell functions.
My interpretation of that line is: if you think you want to use an alias, try writing a function first. Don't use an alias unless the function demonstrably fails to do what you need.
You can use eval like this:
$ runit() { eval $1; }
$ alias ll="ls -l"
$ runit "ll"
eval will expand any alias in $1 before the execution.
One way to solve this problem is to define a shell function rather than an alias.
ll () {
ls -l "$#"
}
The alias is expanded as a macro on command input, whereas the shell function is matched when the command is executed. This is a perfect example of how the shell's macro processor language is good for interactive grace but rather complicates actual programming.
I have a problem regarding an alias file in /etc/profile.d/. This isn't anything important. I'm just interested why it isn't working as expected.
So basically I have the file 00-alias.sh at the path mentioned above and I wanted to make a shortcut which reads a specific line of a file. So this is my code:
alias lnn='sed -n "${1}p" < "${2}"'
With that code I should be able to perform a command like
$ lnn 4 test.txt
However, this doesn't work. I simply get the error
-bash: : No such file or directory
Now I thought, ok, maybe relative paths aren't working because the file is located at the path /etc/profile.d/00-alias.sh
So I went ahead and made a new alias like
alias pwd2='echo $(pwd)'
Then updated the profile.d with
source /etc/profile.d/00-alias.sh
And just tried pwd2 but that echoed the path I was currently in. So in theory the file can be found with the command I wrote. I still tried to pass the file to my alias with absolute path like
$ lnn 4 /var/test.txt
Still same error as above.
But, if I enter the command of the alias in the terminal like
sed -n "4p" < test.txt
It works perfectly fine. No matter if I put quotes around test.txt
And here is another weird thing: If I write
alias lnn='sed -n "${1}p" < ${2}'
without the quotes around ${2} I get the error
-bash: ${2}: ambiguous redirect
In the terminal it works just fine...
So, what am I doing wrong? Does anyone have an idea on this? I'd love to know my mistake. But as I said, this isn't a real problem as I'm just curious why bash behaves like that.
Aliases in bash do not take parameters of any form. Save the pain and use a function instead.
function lnn() {
sed -n "${1}p" < "${2}"
}
Add the function to the file 00-alias.sh and source it once before calling the function from command-line.
source /etc/profile.d/00-alias.sh
lnn 4 test.txt
See more information at BashFAQ/80: How can I make an alias that takes an argument?
You can't. Aliases in bash are extremely rudimentary, and not really suitable to any serious purpose. The bash man page even says so explicitly:
An excerpt from the GNU bash man page, about aliases
.. There is no mechanism for using arguments in the replacement text. If arguments are needed, a shell function should be used.
On a side note the problem has nothing to do with relative paths (or) so, just remember aliases are not allowed in scripts. They're only allowed in interactive shells. If you're writing a script, always use a function instead.
I have alias which contain small script. We generally call alias with username argument.
For small enhancement,we need to call from shell script. I have write into shell script but it looks like that it does not work
/usr/local/buildpkgs/latest/TclDevKit2.6/bin/tclsh
$VDK_PATH/scripts/ves.tcl /bin/csh $vdktmpfile !*;source
$vdktmpfile;/bin/rm $vdktmpfile;
/usr/local/buildpkgs/latest/TclDevKit2.6/bin/tclsh
$VDK_PATH/scripts/vep.tcl $vdktmpfile $SHELL "$prompt:q";
source $vdktmpfile; /bin/rm $vdktmpfile = sample
we generally invoke alias from command line like sample <username>.We need to call this alias from cshell scrip similar way sample <username>.
Does anyone help me to figure out this issue.
Note: I never seen such a long alias if anyone provide me detail it will be great help.
Where is the alias specified? If not in .bashrc but in a general shell script, then you will have to inside of your current shell script:
a) first invoke shell script containing the alias then
b) call alias as you normally do i.e sample <username>
Other alternative is you might want to call your shell script like this:
. ./<script-name>.sh <args>*
as opposed to just
./<script-name>.sh <args>*
the extra period is to execute script in current shell where alias already defined and not create its own process
Alright, so let's say I have a .bash file with this inside of it
lib.bash
#!/bin/bash
function hello_world {
echo "Hello World!"
}
That file won't be called on it's own, instead it'll be called via another bash file, i.e
Startup.bash
#!/bin/bash
bash lib.bash
hello_world
But, if I run Startup.bash I get the error: hello_world: command not found
What am I doing wrong, or is it not possible to do what I'm trying to do on bash.
You can use this command in your startup.bash:
source lib.bash
the source command runs the file in the current shell environment, unlike using bash lib.bash (or . lib.bash) which creates a new, separate environment for that script (and only that script) and is why the function is not carried over.
(source)
why don't you call the function directly inside of the first script?
It would look something like this:
#!/bin/bash
function hello_world {
echo "Hello World!"
}
hello_world
If it is a simple script, shouldn't be a problem at all.
Otherwise try the source command, like minerz029 suggested :)
See if this could be helpful to you as well:
Shell Script Loader
This question already has answers here:
Multiple commands in an alias for bash
(10 answers)
Closed 4 years ago.
I know how to configure aliases in bash, but is there a way to configure an alias for a sequence of commands?
I.e say I want one command to change to a particular directory, then run another command.
In addition, is there a way to setup a command that runs "sudo mycommand", then enters the password? In the MS-DOS days I'd be looking for a .bat file but I'm unsure of the linux (or in this case Mac OSX) equivalent.
For chaining a sequence of commands, try this:
alias x='command1;command2;command3;'
Or you can do this:
alias x='command1 && command2 && command3'
The && makes it only execute subsequent commands if the previous returns successful.
Also for entering passwords interactively, or interfacing with other programs like that, check out expect. (http://expect.nist.gov/)
You mention BAT files so perhaps what you want is to write a shell script. If so then just enter the commands you want line-by-line into a file like so:
command1
command2
and ask bash to execute the file:
bash myscript.sh
If you want to be able to invoke the script directly without typing "bash" then add the following line as the first line of the file:
#! /bin/bash
command1
command2
Then mark the file as executable:
chmod 755 myscript.sh
Now you can run it just like any other executable:
./myscript.sh
Note that unix doesn't really care about file extensions. You can simply name the file "myscript" without the ".sh" extension if you like. It's that special first line that is important. For example, if you want to write your script in the Perl programming language instead of bash the first line would be:
#! /usr/bin/perl
That first line tells your shell what interpreter to invoke to execute your script.
Also, if you now copy your script into one of the directories listed in the $PATH environment variable then you can call it from anywhere by simply typing its file name:
myscript.sh
Even tab-completion works. Which is why I usually include a ~/bin directory in my $PATH so that I can easily install personal scripts. And best of all, once you have a bunch of personal scripts that you are used to having you can easily port them to any new unix machine by copying your personal ~/bin directory.
it's probably easier to define functions for these types of things than aliases, keeps things more readable if you want to do more than a command or two:
In your .bashrc
perform_my_command() {
pushd /some_dir
my_command "$#"
popd
}
Then on the command line you can simply do:
perform_my_command my_parameter my_other_parameter "my quoted parameter"
You could do anything you like in a function, call other functions, etc.
You may want to have a look at the Advanced Bash Scripting Guide for in depth knowledge.
For the alias you can use this:
alias sequence='command1 -args; command2 -args;'
or if the second command must be executed only if the first one succeeds use:
alias sequence='command1 -args && command2 -args'
Your best bet is probably a shell function instead of an alias if the logic becomes more complex or if you need to add parameters (though bash supports aliases parameters).
This function can be defined in your .profile or .bashrc. The subshell is to avoid changing your working directory.
function myfunc {
( cd /tmp; command )
}
then from your command prompt
$ myfunc
For your second question you can just add your command to /etc/sudoers (if you are completely sure of what you are doing)
myuser ALL = NOPASSWD: \
/bin/mycommand
Apropos multiple commands in a single alias, you can use one of the logical operators to combine them. Here's one to switch to a directory and do an ls on it
alias x="cd /tmp && ls -al"
Another option is to use a shell function. These are sh/zsh/bash commands. I don't know enough of other shells to be sure if they work.
As for the sudo thing, if you want that (although I don't think it's a good idea), the right way to go is to alter the /etc/sudoers file to get what you want.
You can embed the function declaration followed by the function in the alias itself, like so:
alias my_alias='f() { do_stuff_with "$#" (arguments)" ...; }; f'
The benefit of this approach over just declaring the function by itself is that you can have a peace of mind that your function is not going to be overriden by some other script you're sourcing (or using .), which might use its own helper under the same name.
E.g., Suppose you have a script init-my-workspace.sh that you're calling like . init-my-workspace.sh or source init-my-workspace.sh whose purpose is to set or export a bunch of environment variables (e.g., JAVA_HOME, PYTHON_PATH etc.). If you happen to have a function my_alias inside there, as well, then you're out of luck as the latest function declaration withing the same shell instance wins.
Conversely, aliases have separate namespace and even in case of name clash, they are looked up first. Therefore, for customization relevant to interactive usage, you should only ever use aliases.
Finally, note that the practice of putting all the aliases in the same place (e.g., ~/.bash_aliases) enables you to easily spot any name clashes.
you can also write a shell function; example for " cd " and "ls " combo here