4

If I create a script in a file like this:

#!/bin/bash
echo "test"

As far I know (as a newbie) is to put it in some folder then make it executable with

chmod +x myscript

and then execute it with something like ./myscript.

I think it's not simple if I have to create file for every command I create. I think it will be more simple if I can just put it in a single file and then make it executable without adding ./ in front of every command that I created. Is it possible?

muru
  • 197,895
  • 55
  • 485
  • 740
Mas Bagol
  • 1,341
  • The question is indeed similar, but not a duplicate of the linked question, because it asks for a method to put several commands into one file. – Hontvári Levente Jan 12 '15 at 15:06

4 Answers4

10

Solution 1: Bash functions

Bash functions behave much the same like commands. You can put functions into - for example - your ~/.bashrc file, like

hello() {
   echo Hello World!
}

Then you can run this like any other command as long as you start it from your shell, and not from a cron job, init script etc:

me@pc:~$ hello
Hello World!

Solution 2: The ~/bin directory

The default ~/.profile file adds the ~/bin directory to your path if that directory exists. So create a bin directory in your home folder, and place your scripts into that that directory. You still have to use chmod +x on the scripts, but you do not have to prefix them with ./

Do not forget to relogin after creating the bin directory!

4

You need to add the ./ to run commands from scripts in the local directory, because commands that do not contain / in their name are looked up only in the directories mentioned in the $PATH value. Normally that value contains only absolute paths, and in particular does not contain a path ., so that the current working directory is not looked at. This is a Good Thing, because otherwise one could try to trick users into executing scripts without intending to do so by placing scripts with names matching common commands such as ls in certain directories; also it is not usually very practical to make certain commands only visible when the current directory has some specific value.

The natural solution is to have a certain directory were you place the private commands that you want to be able to call, and ensure that the (absolute) name of that directory occurs in $PATH. The traditional place for such a directory is $HOME/bin.

  • 1
    +1, don't put . in your $PATH. Just asking to get bitten by a tar archive that has a file called ls in it, containing rm -rf $HOME. So you shoot yourself in the foot someday looking at files you shouldn't be trusting. – Peter Cordes Jan 11 '15 at 14:14
0

I have a bunch of aliases and shell functions defined in my ~/.bashrc

alias ll='ls -lh'
alias li='ls -lhi'
alias lll='ls -lhL'
alias l='ll'
complete -F _longopt l ll lll li  # this doesn't actually work

psg(){ ps aux | grep ${*:-$USER} | grep -v grep; }
psgw(){ ps auxww | grep ${*:-$USER} | grep -v grep; }

# expand aliases for sudo
alias sudo='sudo '
alias imv='imv -i'
alias mv='mv -i'
alias cp='cp -i'
alias rm='rm -i'
alias prealloc-mv='rsync --remove-source-files --sparse --preallocate -aH'
alias m=less
export LESS=iMRj5
alias j='jobs -l'
alias dr='disown -r'

cmpll() { ll "$@"; cmp "$@" && echo identical; }
findll() { find "$@" -exec ls -dlh --color=auto {} +; }
findinamell() {
    local i  args=()
    for i in "$@";do
            args+=( '-iname' )
            args+=( "*$i*" )
    done
    findll "${args[@]}";
}

As others have pointed out, ~/bin is in your $PATH by default, if it exists, so you can put things that are too big for an alias or shell function there. I actually have several really small scripts in my ~/bin, IDK why I decided to make them files instead of aliases. Search for "COMMAND EXECUTION" in the bash man page for more details about how commands are interpreted. man bash.

If I'm cooking up some commands that are only applicable to something I'm working on in a certain directory, I might well put the commands in a file there, and run it with ./do-stuff.sh. Your fingers will get used to typing ./ pretty quickly. You might also keep a text file of useful commands you've used, along with a description of what they do. I do this sometimes when I don't think it's worth the time to turn it into a function or script that takes parameters, but instead just paste it in and edit it as appropriate. e.g. for playing back audiobooks, I often use:

mpl() { t=2200; mplayer -ss $(($t * ($1%2))) -endpos $(($t+5)) disc$(printf '%02d' $((1 + $1/2)))-38.mp3; date; }; mpl 4

(this plays 2200 seconds of audio, starting at either the beginning ($1 odd), or 2200sec in, to one of many numbered tracks. Basically map a linear index into a set of audio files that are each two listening-chunks long.)

I can up-arrow and edit the very end of the command line with my monitor off, while I'm falling asleep. I use a shell function so the part I need to edit is right at the very end. Aliases only work if all the arguments can go right at the end of the fixed part of the command.

I'm sure there's a ton of good stuff out there if you google, but there's probably a ton of outdated and less-useful stuff too, and I don't want to take time to evaluate a guide right now.

Peter Cordes
  • 2,197
0

You can always out it in the bin directory. Or, let's say it's a she script at the location of /home/user/Desktop/hello.sh you can open up ~/.bashrc and add to it

    hello() {
    '/home/user/Desktop/hello.sh'
    }

Then, you can execute 'hello' in the terminal and it should work perfectly.

crank123
  • 23
  • 1
  • 1
  • 7