Intro to Linux and the Bash command line, pt II
Published 2018-12-31 on Yaroslav's weblog
This text is also available in other languages: Русский
So the year is coming to an end, and I didn't follow up on the first part of these mini tutorial/guide/introduction. Might as well end the year on a good note and write at least one post this last month.
In this part I will be writing about some more aspects of Linux and Unix-like systems and tools that will come in handy when using the terminal. All or most of these tools are a standard part of Linux and Unix/Unix-like systems.
I didn't get into detail in the previous part of this guide on the file manipulation side of things. However it is a crucial part of any computer system, after all they wouldn't be as useful as they are if you couldn't create, edit and delete files.
Usually, the way you would go about creating and editing files is by using the corresponding programs. Like for example, vim to create and edit text files. However, there's also a utility to create blank files called touch.
You can make a blank file by writing touch followed by the path of the file you wish to create, like this
user@host:~$ touch example.txt
Now we have an empty file at "/home/user/example.txt". Although I kind of lied when I said that this command is for making blank files. In reality, what it does is check if such file exists, if it does, it modifies the date and time of access and modification, otherwise it makes a new empty file, like in our case. Most of the time you won't really need this command, since you would actually be creating files through programs or means, though it does come in handy sometimes.
Now on to something more interesting, making directories. This one is quite simple, and the command for that is mkdir. For example
user@host:~$ mkdir foo
In this case we have created a new folder called "foo" in "/home/user/". But remember that we are passing paths here, which can be relative or absolute (if you don't know or remember what this means, check the first part of this guide). In our case we were using a relative path, with just the name of the directory to create.
If we were to indicate an absolute path like "/home/user/foo" we would need to make sure that directories "home" and "user" already exist. However, there's a useful argument we can pass to mkdir to make parent directories if needed, -p
user@host:~$ mkdir -p /tmp/foo/bar
In this case, if directory "foo" doesn't exist, mkdir will make it for us along with "bar" inside it.
Moving and renaming
This one is pretty simple, and both actions are handled by the same command, mv, which is short for move.
If you want to rename a file or directory, simply "move" it to the same destination directory with a new/different name, for example
user@host:~$ mv untitled titled
If you want to move it to a different location, just indicate that path as the second argument. Remember that we are using paths here, and we use either absolute or relative paths
user@host:~$ mv titled Documents/titled
Copying files is similar to moving them, except that the command is different, cp
user@host:~$ cp titled Documents/titled2
However, copying directories is different. To copy directories you have to use a special flag, the -r flag. This flag means that the operation ought to be recursive, that is to copy every file and subdirectory in that directory along with the directory (and files in those subdirectories and files the subdirectories of the subdirectories and... yeah recursion, you get it) to the destination path. So we would do something like this
user@host:~$ cp -r dir dir-copy
Removing files is pretty simple, just use rm followed by the path of the file, for example
user@host:~$ rm title
However, removing directories is a little bit trickier. One option would be to use the command rmdir, however, the directory has to be empty before you can remove it.
The second option, is to use the same command as we used with files, but passing it the -r flag so that it removes files recursively, similar to what we did with the copy (cp) command. Do watch out, as it will remove the directory along with everything that is in it.
So to remove a directory and everything in it, we input something like this
user@host:~$ rm -r dir
This command also has another flag to forcefully remove files without prompting, the -f flag. This might be useful when you are removing files recursively and there might be some special files, like hidden files (the ones with a dot as the first character) and you don't want to be prompted for each and everyone of them.
Thread REALLY carefully when using this command though, especially if you are issuing it as root. You don't wanna issue a "sudo rm -rf /" and end up with a borked system and lost files. Unless you are some kind of sadist or something.
An example of when it might be useful, is when you need to delete a git repository from your computer, since it contains a lot of special hidden files which git uses to keep track of your commits and other stuff. So to remove it, we do
user@host:~$ rm -rf somerepo
The Unix or Unix-like user and permissions systems, is a robust system for managing what particular users can do with certain files and directories. This allows to create a secure environment, especially when there are multiple users using one computer.
Every file has three types of permissions which dictate what can be done with it. Each permission is represented by a single letter
- r - read: the user can read/view the file.
- w - write: the user can write/modify (this includes deleting) the file.
- x - execute: the file can be run or executed by the user, if it is a program or script.
There are as well three different sets of people the permissions and ownership might apply to. These are
- u - user/owner: the one user that owns the file. Usually it is the user that created the file, but ownership can be modified.
- g - group: every file has a group it belongs to. The group can be a one user group (every user has their own one-user group), or a common group with multiple users.
- o - others: everybody else who is not either in the group or the owner.
If you read the first part of this guide you might remember that I mentioned using the command "ls -l" to list the contents of the directory with details about the files, including permissions
user@host:~/Documents$ ls -l drwxr-xr-x 2 user user 4.0K Jul 18 04:20 Books -rwxr-xr-- 1 user group 350 Jul 18 04:20 run.py -rw-r--r-- 1 user user 1.2M Jul 18 04:20 picture.png
As mentioned in the first part, the first ten characters of a row of the output is what tells us about the permissions of the given file in that row.
The first character in that sequence tells us if it is a normal file, or a directory. If it has a d, it is a directory (duh), if it has a dash, it is a normal file. It can be another letter, like an l for a symbolic link (a topic for another day).
The next 9 characters are divided in subsequences of three letters, each for a set of people. The first three characters after the file type one are the permissions for the owner, the next three are for the group, and the last three for others.
In each of this subset of three characters, the permissions are in the order of read, write, and execute. So a letter means that that said set of users have said permission, and its absence means the lack of that permission.
Let's take for example the "run.py" file. By the information there we can see that it is a normal file (no d (that's what she said)), its owner (user) can read, write and even execute it; the group users (in group group) can read and execute it, but not write to it; and the others can just take a look at its contents.
You might have noticed that directories tend to have the "x" part of the permissions, however, this means something a little bit different on directories than on files. It doesn't mean that you can execute but rather that you can "search it", or in other words, access files inside of it. Because having the "read" permission on a directory only means that you can take a look at what files are inside of it, and write that you can put files inside the directory.
There is a really useful command that allows us to change permissions on files, chmod. It is short for change file mode bits.
To change the permissions on the file you input chmod followed by the permissions and the path of the file. There are two ways of setting the permissions, the easy and long one using letters, and the short but not as easy way with octal "permission bits". We'll take a look at the easy one first.
The easier way is made up of three parts
- Who - user/owner, group, others or all (u, g, o, or a)
- Revoke or grant, "+" to grant, "-" to revoke
- The permission we are setting - read, write or execute (r, w, or x)
So let's suppose we have a script we want to set the execute permission for so that any user in the computer can execute it.
user@host:~/Documents/stuff$ ls -l -rw-r--r-- 1 user group 420 April 20 6:59 script.sh user@host:~/Documents/stuff$ chmod a+x script.sh -rwxr-xr-x 1 user group 420 April 20 6:59 script.sh
As we can see, after executing the command, every user on the computer now has execute permission on the script. Now let's say that we want to revoke read permissions for everybody except for the owner (user), we could execute o-r and then g-r, but we can also combine them, like so
user@host:~/Documents/stuff$ chmod go-r script.sh -rwx--x--x 1 user group 420 April 20 6:59 script.sh
Now onto the short way. This one's a bit harder to remember as you have to have some understanding of binary. Basically the way it works is that you set the permissions by passing three octal numbers (i.e., 0-7) that each represent the permission bits for each set of people (user/owner, group, others).
As it is we have three possible permissions (read, write and execute) and 2^3 just so happens to be 8 (possible combinations), that's why it is in octal. Here's a table to help you out
Basically what this means, is that when we have a 1, said permission is granted, when it is 0, it is not. So for example, 6 means that read and write have been granted, but not execute, because 6 => 110 => rw-.
So let's say for example that we want to set the permissions of file so that the owner can read, write, and execute, the group can read and execute, and others can only execute. It would look something like this
user@host:~/Documents/stuff$ chmod 751 script.sh user@host:~/Documents/stuff$ ls -l -rwxr-x--x 1 user group 420 April 20 6:59 script.sh
If you are changing the permissions of a directory, the permissions will apply only to the directory itself and not to the files and subdirectories inside of it, unless you use the recursive flag -R (note that in the case of chmod and chown it is a capital R).
Changing the owner of a file is easier than changing permissions, since less variables are involved. To change owner we use the chown command, for example, change the user that owns a file
user@host:~/.logs$ ls -l -rw-r--r-- 1 root root 69 April 20 6:59 some.log user@host:~/.logs$ sudo chown user some.log user@host:~/.logs$ ls -l -rw-r--r-- 1 user root 69 April 20 6:59 some.log
As the file doesn't belong to the same user initially, we need to use sudo elevate our permissions to "super user". Note that in order to be able to use sudo or "elevate your permissions" your user needs to be either in the sudoers file or in other distros in the "wheel" group, or both. I won't go into details on how to do that, since most probably your user is already in the sudoers file, and a quick search on the internet will give you the information needed.
Now let's say that you wanted to change both the user and group that file belongs to, we would do like this
user@host:~/.logs$ ls -l -rw-r--r-- 1 root root 69 April 20 6:59 some.log user@host:~/.logs$ sudo chown user:group some.log user@host:~/.logs$ ls -l -rw-r--r-- 1 user group 69 April 20 6:59 some.log
Just as with chmod, if you want to change ownership recursively in a directory, you need to use the -R flag.
I forgot to mention in the previous part how to write paths with spaces. You cannot write paths with spaces just like that, since spaces are treated as the separator between arguments.
There are two ways of writings paths and filenames (and other arguments) with spaces. One is to put the argument between quotation marks, like for example
user@host:~/Documents$ rm "Shopping List.txt"
Another is to use an escape character, i.e. just put a backslash () before the space, like this
user@host:~/Documents$ rm Shopping\ List.txt
One more thing that I wanted to mention is the man(ual) pages. Basically all Linux distros come with man pages.
You don't always have to resort to the internet if you don't remember how to use a command, like what flags a command accepts, what are the order of the arguments, etc. You might not have internet one day, and you might to resort to good ol' offline resources, and the man pages are a good one.
Besides, it is sometimes faster and easier to not have to leave the terminal to look up the information.
To read the man(ual) pages of a command, input "man" followed by the name of the command, e.g. "chmod", and it will provide you with almost all the information that you need.
You can use vim keys (hjkl), or the arrow keys to scroll. Type /
This is all for this part. Happy 2019!
© 2018—2022 Yaroslav de la Peña Smirnov.