3

I wrote a function to use in bash to automatically mount a directory in ~/tmp and create one if it's not there:

# mkdir & mount auto
mnt() {
    dir="$1";
    mkdir ~/tmp/$dir;
    /usr/bin/sudo mount /dev/$dir ~/tmp/$dir;
    cd ~/tmp/$dir;
}

A few questions ...

dir="$1";

sets variable dir to whatever the input is after mnt
- does the $1 need to be encased in "" and does there need to be a ; after each line? would it work without the ;?

/usr/bin/sudo mount /dev/$dir ~/tmp/$dir;

I watched a youtube video Everything You Need to Know About $PATH in Bash

that in scripts I should write full paths ...

/usr/bin/sudo 

rather than ...

sudo

what is the reasoning behind this?

Rui F Ribeiro
  • 56,709
  • 26
  • 150
  • 232
m147
  • 63
  • 4
    How can you write a script via trial and error without learning what each line does via seeing what effect each line has? – RonJohn Dec 30 '17 at 21:03
  • @RonJohn Code can be bad and nonetheless have (in a certain situation) the desired effect. Watching your code do what it is supposed to does not tell you whether you should use different code. – Hauke Laging Dec 30 '17 at 21:29
  • @RonJohn, it's not so much I didn't understand the commands I was using rather I wanted a deeper understanding as explained by those with full knowledge of the matter. I understand the bash commands and I was scripting the function from another function I had pulled earlier off the net as an example. My approach was not simply to type "function to mkdir and mount" into google and copy/paste, but rather to write it myself and make mistakes and learn from it. – m147 Dec 31 '17 at 03:13
  • As if bash were ever a mystery reserved for liches of comp.sci... use && to abort if a line fails, and bash -n script.sh to verify before exec. @RonJohn should reserve his arrogance to a C/C++ forum where it would be both traditional and constructive. set -eu -opipefail is a railing alongside the torrent. A crutch, however, it is not. – user2497 Dec 31 '17 at 06:42
  • @HaukeLaging apart from gratuitous semicolons and lack of &&/|| or enclosing () to subshell, this code is not ‘bad’. ubuntu base has worse scripts in /etc. – user2497 Dec 31 '17 at 06:51

2 Answers2

7

A better version of this function:

mnt() {
  typeset dir # for local scope for the variable.
              # assumes ksh88/pdksh/bash/zsh/yash. Replace typeset with
              # local for ash-based shells (or pdksh/bash/zsh)

  dir=$1 # here it's the only place where you don't need the quotes
         # though they wouldn't harm

  mkdir -p -- ~/tmp/"$dir" || return
     # quotes needed. mkdir -p creates intermediary directories as required
     # and more importantly here, doesn't fail if the directory already
     # existed.
     # We return from the function if mkdir failed (with the exit status
     # of mkdir). The -- is for the very unlikely even that your $HOME starts
     # with "-". So you may say it's a pedantic usage here. But it's good
     # habit to use it when passing an arbitrary (not known in advance)
     # argument to a command.

  sudo mount "/dev/$dir" ~/tmp/"$dir" || return
     # Or use /usr/bin/sudo if there are more than one sudo commands in $PATH
     # and you want to use the one in /usr/bin over other ones.
     # If you wanted to avoid calling an eventual "sudo" function  or alias 
     # defined earlier in the script or in a shell customisation file, 
     # you'd use "command sudo" instead.

  cd -P -- ~/tmp/"$dir" # another pedantic use of -P for the case where
                        # your $HOME contains symlinks and ".." components
}

Semicolons are not needed. While at the prompt of your shell, you write:

cd /some/where
ls

Not

cd /some/where;
ls;

It's no different in scripts. You use ; to separate commands on one line as in:

cd /some/where; ls

Though, then you'd rather write:

cd /some/where && ls

That is not run ls unconditionally, but only if cd is successful.

  • Perfect explanation! – PesaThe Dec 31 '17 at 00:19
  • NIce. Thank you for the explanation. It clears up a lot. And it's a nice improvement on my function, I will add the bits you suggest. What exactly does the return bit do? You mention it has to do with if the function fails but how exactly does it work and what does the || do? Is it similar to piping commands? Also the typeset at the start, could you explain it further? – m147 Dec 31 '17 at 03:22
5

Questions:

  • does the $1 need to be encased in ""

    Short answer is yes

More Reading

  • does there need to be a ; after each line? would it work without the ;?

    The ; is a command separator and is only necessary if multiple commands are on the same line like: echo "Hello, World"; echo. When the commands are on separate lines like in your script it is unecessary but wont break anything.

  • Why should I specify a full path rather than just the command name?

    When you simply type a command name your path is parsed for the first occurrence of that command. It is not uncommon to have multiple commands in different locations, especially with the existence of GNU tools and other variations of the same commands. If you don't specify the full path of the command you are using, your shell will decide which to use, and it may not be the one you really want.

I sort of disagree with always specifying the full path because in my experience it usually isn't necessary and I only care that it finds some version of the tool. There are exceptions though, but I think you should better understand them before considering them. For example in my environment we have mostly unix machines that do not default to GNU tools, however many of the tools are installed on the machines so if I need to use the GNU version of a tool against one of those machines I need to specify the full path to that tool.


mnt() {
    dir="$1";                                   # Sets the value of dir to your first positional parameter
    mkdir ~/tmp/$dir;                           # Creates your a directory named after the value of $dir in $HOME/tmp/
    /usr/bin/sudo mount /dev/$dir ~/tmp/$dir;   # Mounts the device in /dev/$dir to your newly created folder (You better hope you set $1 properly)
    cd ~/tmp/$dir;                              # changes to your newly created/mounted directory.
}
jesse_b
  • 37,005
  • 3
    About the 3rd - IMO writing /usr/bin/sudo is not really desirable. What if I've just compiled a new version of sudo in ~/sudo and added ~/sudo to my $PATH - I'd prefer all scripts to use it. Sometimes /usr/bin/env <shell> is used instead of /usr/bin/bash as the shebang because you're not sure where the shell is (of course you still have to know where /usr/bin/env is). Finally, how can one be sure that there actually is sudo binary in /usr/bin? System administrator may prefer to keep it in /usr/local/bin for example. – Arkadiusz Drabczyk Dec 30 '17 at 19:46
  • 1
    Since we are discussing bash, you might just mention assignment dir=$1 without quotes is fine, even if you recommend otherwise. – PesaThe Dec 30 '17 at 20:28
  • 1
    @PesaThe "KISS" principle applies: always quote variables when they're used. – Chris Davies Dec 30 '17 at 20:33
  • @roaima It is still worth mentioning that it's not necessary in some cases, don't you think? Why not add one sentences that adds something valuable to the answer. – PesaThe Dec 30 '17 at 20:35
  • 4
    @PesaThe "Don't you think" -- Absolutely not. There is no good reason to not quote and a thousand good reason to quote. Constantly talking about the the rare cases where it doesn't matter wont benefit anyone. Also this question is about shell not necessarily bash. – jesse_b Dec 30 '17 at 20:37
  • 6
    @PesaThe not for beginners, no. The video s/he watched is confusing enough. Keep it simple for beginners. Think back to your maths course. Originally you could only add positive integers, then you got taught negative numbers. Later you were told you can't square root a negative number. Later still you may have been told you can. It depends on your experience. I wouldn't teach i to a primary school child. Back to variables. There are very very few instances where an unquoted variable is an explicitly correct thing to do. – Chris Davies Dec 30 '17 at 20:38
  • @roaima I don't see how something like this: When assigning to a variable var=$something, quotes are not necessary. However, best practice is to quote all parameter expansions, would harm. – PesaThe Dec 30 '17 at 20:41
  • 1
    @roaima Answers should be simple for beginners, sure. But they should also be correct. Saying the quotes have to be there, is false. – PesaThe Dec 30 '17 at 20:44
  • 1
    @PesaThe Because we know from experience that lots and lots of people will only read the part up until that they feel they've got an answer to their question, and they will then apply what they have read in contexts it was not indended for. "When assigning to a variable var=something, quotes are not necessary" is the part that will likely stick in their mind. If you're going to specify edge cases, always start with the generally safe case. In this case, omitting quotes doesn't really provide any benefit, so for someone new to bash scripting, there's little reason to delve deeply into it. – user Dec 30 '17 at 20:47
  • 1
    Same reason why I always quote variable names as in ${XX} in my bash scripts -- in 99% of the cases it makes no difference, but then there's that 1% edge case where it does and lack of braces causes untold trouble in trying to figure out what's wrong with your script. Generally, it's best to establish safe habits first; deviate from them only later, when you know that it is safe to do so, and why it is safe to do so, and why you're doing so in the first place. – user Dec 30 '17 at 20:47
  • 1
    @MichaelKjörling Maybe it's just me but I prefer to get thorough answers. Not just answers: Oh because you are a beginner, quote everything, OK?. I am obviously exaggerating. But I am sure the answer can be rephrased just a little to provide further detail while still complying with best practices. People like OP might come across answers that are written by users not using quotes when assigning to variables. I think it is appropriate to explain that it is not incorrect. Also, the answer says the quotes have to be there, but leaves all other expansions unquoted! – PesaThe Dec 30 '17 at 20:53
  • @Jesse_b, awesome! Thanks for your explanation. I have a better understanding of it all now. – m147 Dec 31 '17 at 03:26
  • @MichaelKjörling you mention something about curly braces ${XX}. Is it similar to using quotes around variables? I was reworking some scripts that display path in terminal titlebars to better suit my needs and it used the curly braces around variable names. In my case, to play around with it and see effects, it did not make an apparent difference whether they were there or not. For some context, this is what I'm talking about link and link. – m147 Dec 31 '17 at 03:37
  • @m147 I recommend asking that as a separate question. – user Dec 31 '17 at 11:18
  • @MichaelKjörling ok. Might do that. I'll look into with Google first :D – m147 Dec 31 '17 at 11:20