top - display tasks and system status in Unix

Hi! If you're new here, you may want to subscribe to my RSS feed. Thanks for visiting!

top is a basic Unix command which is very useful for observing the current state of your Unix system, by default presenting you the list of top users of your system's resources - CPU shares and memory.

Basic usage of the top command

By default, you run top without any parameters, and it shows you a full screen (or full window of your terminal) with the current status of your system and a list of processes using most of its CPU:

ubuntu$ top
top - 13:29:09 up 2 days,  7:13,  4 users,  load average: 0.07, 0.02, 0.00
Tasks: 148 total,   1 running, 147 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.6%us,  0.5%sy,  0.0%ni, 97.3%id,  1.6%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:   4051792k total,  4026104k used,    25688k free,   359168k buffers
Swap:  4096492k total,    24296k used,  4072196k free,  2806484k cached
  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
 7629 greys     20   0  749m 291m  28m S    1  7.4  16:51.40 firefox
19935 greys     20   0  133m  14m  10m S    0  0.4   2:38.52 smplayer
    1 root      20   0  4020  880  592 S    0  0.0   0:00.96 init
    2 root      15  -5     0    0    0 S    0  0.0   0:00.00 kthreadd
    3 root      RT  -5     0    0    0 S    0  0.0   0:00.04 migration/0
    4 root      15  -5     0    0    0 S    0  0.0   0:00.90 ksoftirqd/0
    5 root      RT  -5     0    0    0 S    0  0.0   0:00.00 watchdog/0
    6 root      RT  -5     0    0    0 S    0  0.0   0:00.06 migration/1
    7 root      15  -5     0    0    0 S    0  0.0   0:01.32 ksoftirqd/1
    8 root      RT  -5     0    0    0 S    0  0.0   0:00.00 watchdog/1
    9 root      15  -5     0    0    0 S    0  0.0   0:02.14 events/0
   10 root      15  -5     0    0    0 S    0  0.0   0:01.44 events/1
   11 root      15  -5     0    0    0 S    0  0.0   0:00.00 khelper
   44 root      15  -5     0    0    0 S    0  0.0   0:01.26 kblockd/0
   45 root      15  -5     0    0    0 S    0  0.0   0:01.98 kblockd/1
   48 root      15  -5     0    0    0 S    0  0.0   0:00.00 kacpid
   49 root      15  -5     0    0    0 S    0  0.0   0:00.00 kacpi_notify
  153 root      15  -5     0    0    0 S    0  0.0   0:00.00 kseriod
  203 root      15  -5     0    0    0 S    0  0.0   0:03.56 kswapd0
  246 root      15  -5     0    0    0 S    0  0.0   0:00.00 aio/0
  247 root      15  -5     0    0    0 S    0  0.0   0:00.00 aio/1
 1595 root      15  -5     0    0    0 S    0  0.0   0:00.00 ksuspend_usbd
 1601 root      15  -5     0    0    0 S    0  0.0   0:00.02 khubd
 1612 root      15  -5     0    0    0 S    0  0.0   0:00.08 ata/0
 1615 root      15  -5     0    0    0 S    0  0.0   0:08.28 ata/1
 1616 root      15  -5     0    0    0 S    0  0.0   0:00.00 ata_aux

Output of the top command explained

These are the elements which default top output consists of:

Unix system uptime and average load

This is the line of top which confirms how many hours (or even days!) your system has been up, shows you the number of logged in users, and reports the average system load numbers for the last minute, 5 minutes and 15 minutes.

top - 13:29:09 up 2 days,  7:13,  4 users,  load average: 0.07, 0.02, 0.00

In this line:

  • 13:29:09 is the current time
  • 2 days, 7:13 is the uptime
  • 4 users shows how many users currently use your system
  • 0.07 - average load for the last minute
  • 0.02 - average load for the last 5 minutes
  • 0.00 - average load for the last 15 minutes

Unix tasks stats

Here you can see how many tasks are currently running on your system. Tasks here mean processes, and the main listing will show you the task names (in the COMMAND column) and the PIDs.

Tasks: 148 total,   1 running, 147 sleeping,   0 stopped,   0 zombie

CPU(s) status

Current CPU state, averaged for the number of CPUs installed in your system, is represented in this line:

Cpu(s):  0.6%us,  0.5%sy,  0.0%ni, 97.3%id,  1.6%wa,  0.0%hi,  0.0%si,  0.0%st

Here are the explanations for each parameter:

  • us - User CPU time. The time the CPU has spent running users’ processes with default priorities
  • sy - System CPU time. The time the CPU has spent running the kernel and its processes
  • ni - Nice CPU time. The time the CPU has spent running users’ proccess that have been prioritized up using nice command
  • wa - I/O wait. Amount of time the CPU has been waiting for I/O operations to complete
  • hi - Hardware IRQ. The amount of time the CPU has been servicing hardware interrupts
  • si - Software Interrupts. The amount of time the CPU has been servicing software interrupts
  • st - Steal Time. The amount of CPU ’stolen’ from this virtual machine by the hypervisor for other tasks (such as running another virtual machine) - a fairly recent addition to the top command, introduced with the increased virtualization focus in modern operating systems

Physical memory usage stats

Memory stats line gives you a summary of how much physical memory you have on your system, and how much of it is currently used or available for the use.

Modern Linux systems are buffering quite a lot for improved performance, which means you rarely get to see all your physical RAM free - the more your system stays up and running, the more of its recently used data ends up being buffered.

In this line, you can see how quite a bit is taken up by the buffers:

Mem:   4051792k total,  4026104k used,    25688k free,   359168k buffers

Swap usage stats

Swap statistics highlight how actively your system uses the swap space - most of it should not be used on a healthy system, although seeing substantial amount of swap memory cached is quite normal. Bear in mind that these are caches held in physical memory, so in this example these 2.8Gb of cached swap is responsible for most of the 4Gb physical RAM taken up and reported as used in the above stats for memory

Swap:  4096492k total,    24296k used,  4072196k free,  2806484k cached

List of the tasks (processes) running on your system

This is the main part of the top output, which looks like this (output is abridged):

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
 7629 greys     20   0  749m 291m  28m S    1  7.4  16:51.40 firefox
19935 greys     20   0  133m  14m  10m S    0  0.4   2:38.52 smplayer
    1 root      20   0  4020  880  592 S    0  0.0   0:00.96 init
    2 root      15  -5     0    0    0 S    0  0.0   0:00.00 kthreadd
    3 root      RT  -5     0    0    0 S    0  0.0   0:00.04 migration/0
    4 root      15  -5     0    0    0 S    0  0.0   0:00.90 ksoftirqd/0
    5 root      RT  -5     0    0    0 S    0  0.0   0:00.00 watchdog/0
    6 root      RT  -5     0    0    0 S    0  0.0   0:00.06 migration/1

As you can see from this list, you're given all the vital information about each process running on your Unix system:

  • PID - process ID
  • USER - username for the owner of each process
  • PR - process priority (RT means a Real Time priority class - used for system processes)
  • NI - priority set by nice utility
  • VIRT - the amount of virtual memory used by a process: code, data and shared libraries plus pages that have been swapped out
  • RES - the resident part of a process - how much of it resides in the physical memory (non-swapped memory)
  • SHR - shows you the size of potentially shared memory segments for a process
  • S - the current state of each process
  • %CPU - percentage of the time shares CPU spends running a particular process
  • %MEM - percentage of the physical memory of your system which is used by each process
  • %TIME+ - total time CPUs spent running each process
  • COMMAND - a command used to initiate each process.

I'll be sure to revisit and expand this page at some later stage.

See also:

date - print or set the system date and time

date is a basic Unix command for getting or setting the current time and date on your system. Because it's the easiest way to get current time, this command is extensively used in Unix scripting.

Getting current time and date in your Unix system

The default usage of this command is simple and requires no additional command line parameters:

ubuntu$ date
Wed Jun 11 11:43:52 IST 2008

Continue reading →

getent - get entries from administrative database

getent is Unix command which helps you query one of the following administrative databases in Unix: passwd, group, hosts, services, protocols, or networks.

Administrative databases in Unix

As you can probably see from their names, the administrative databases are here to help you gather the most vital information about your environment:

  • passwd - can be used to confirm usernames, userids, home directories and full names of your users
  • group - all the information about Unix groups known to your system
  • services - all the Unix services configured on your system
  • networks - networking information - what networks your system belongs to
  • protocols - everything your system knows about network protocols

How to use getent

My home PC has a hostname of ubuntu. If I ever need to double-check which IPs this hostname points to, here's how I can use getent:

ubuntu$ getent hosts ubuntu
127.0.1.1       ubuntu
192.168.0.2     ubuntu

Using getent to find a UID by username

getent accepts various keys when searching in databases. For the passwd one, you can user either username or user id (UID) to search the database.

ubuntu$ getent passwd greys
greys:x:1000:1000:Gleb Reys,,,:/home/greys:/bin/bas

Using getent to find a username by UID

Like I said, the opposite will work as well:

ubuntu$ getent passwd 1000
greys:x:1000:1000:Gleb Reys,,,:/home/greys:/bin/bash

See also:

  • id - print user identity
  • who - see who is logged into the system

locate - quickly find files in Linux

Today I'd like to show you one more option you have when searching for files in Linux. If you have a locate tool installed, you'll be able to find any file almost instantly.

How does locate command work?

locate uses a pretty simple principle - instead of going through your filesystem directory tree every time you need a certain file found, it consults a database which stores locations of most files in your system. The locate database (locatedb) is updated nightly with a separate command. The update occurs during night hours when peak usage of your system is very unlikely, but this means that using such a database through the day will provide instant results.

Continue reading →

file - show the type of a file in Unix

file is one of the basic Unix commands which helps you confirm exactly what kind of files you're working with. Using a special database of signatures for various types of files, it reads the first few bytes of a specified file and shows you whether it matches one of the signatures, thus confirming the file type.

file command: basic usage

The simplest way to use the file command is to run it and specify one or more file names as command line parameters. The file type description you expect will be given in plan English, showing you whether a file is a script or an executable, an ASCII text or a binary data:

rhel$ file /etc/passwd
rhel$ file /bin/csh
rhel$ file /bin/tcsh
/bin/tcsh: ELF 64-bit LSB executable, AMD x86-64, version 1 (SYSV), for GNU/Linux 2.4.0, dynamically linked (uses shared libs), stripped

Examples of file types in Linux

Playing with the file command is fun. You can identify all sorts of files with this little command, but it's important to be able to read its output correctly.

Below I give you just a few most common file types examples, taken from a Red Hat Enterprise System (RHEL).

This is how a typical shared library will be identified:

rhel$ file /lib/libc-2.3.2.so
/lib/libc-2.3.2.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), not stripped

Note the 32-bit which confirms the bit-ness of this file and the Intel 80386 which confirms the architecture.

That's the same library in 64bit:

rhel$ file /lib64/libc-2.3.2.so
/lib64/libc-2.3.2.so: ELF 64-bit LSB shared object, AMD x86-64, version 1 (SYSV), not stripped

See how 32-bit is now changed to 64-bit, and AMD x86-64 shows the new architecture for it?

Binaries will look somewhat different, although the bit-ness and architecture will still be shown:

rhel$ file /bin/ls
/bin/ls: ELF 64-bit LSB executable, AMD x86-64, version 1 (SYSV), for GNU/Linux 2.4.0, dynamically linked (uses shared libs), stripped

In this example, the important field is executable, which confirms this is a file you can run (vs previous example with shared objects which you can't run directly)

Examples of file types in SPARC Solaris

Just to show you that Unix file formats aren't this different, here's a few examples from SPARC Solaris 10 system.

First, a library - in 32bit and 64 bit forms:

sparc$ file /lib/libc.so
/lib/libc.so:   ELF 32-bit MSB dynamic lib SPARC32PLUS Version 1, V8+ Required, dynamically linked, not stripped, no debugging information available
sparc$ file /lib/64/libc.so
/lib/64/libc.so:        ELF 64-bit MSB dynamic lib SPARCV9 Version 1, dynamically linked, not stripped, no debugging information available

Observe how bit-ness is still shown where you'd expect to see it, as well as SPARC-based architecture (SPARC32PLUS for 32bit and SPARCV9 for 64-bit).

Here's how a kernel driver will look:

sparc$ file /kernel/drv/sparcv9/zfs
/kernel/drv/sparcv9/zfs:        ELF 64-bit MSB relocatable SPARCV9 Version 1

And that's how a typical SPARC Solaris binary is identified:

sparc$ file /bin/ls
/bin/ls:        ELF 32-bit MSB executable SPARC Version 1, dynamically linked, stripped

See also:

basename - strip directory and suffix from a full path to a file

basename is a very simple but useful Unix command which is used mostly in shell scripting. Taking a full path to a file as a parameter, it then stips the directory names from it and returns you just the name of a file.

Note: basename is a string stripping command - it simply returns you the last portion of a provided full path. It does not verify whether this portion is an actual file.

How to use basename command

This is how basename is invoked:

ubuntu$ basename /etc/network/if-down.d/postfix
postfix

basename in shell scripting

An example of using the basename command is shown below. This command line takes the input from a standard output from the find command and outputs only the names of the files. While there's not much practicality in doing this, it's a great way to show how basename works.

Here's the standard find output:

ubuntu$ find /etc/network/
/etc/network/
/etc/network/if-down.d
/etc/network/if-down.d/wpasupplicant
/etc/network/if-down.d/postfix
/etc/network/if-post-down.d
/etc/network/if-post-down.d/wpasupplicant
/etc/network/if-post-down.d/wireless-tools
/etc/network/if-pre-up.d
/etc/network/if-pre-up.d/wpasupplicant
/etc/network/if-pre-up.d/wireless-tools
/etc/network/if-up.d
/etc/network/if-up.d/wpasupplicant
/etc/network/if-up.d/mountnfs
/etc/network/if-up.d/ntp
/etc/network/if-up.d/ntpdate
/etc/network/if-up.d/postfix
/etc/network/interfaces

And this is how only the filenames are extracted. Note, how for some parameters you see not the filenames, but directory names like if-down.d, simply because they're the last part of a string returned by the find output:

ubuntu$ for f in `find /etc/network/`; do basename $f; done;
network
if-down.d
wpasupplicant
postfix
if-post-down.d
wpasupplicant
wireless-tools
if-pre-up.d
wpasupplicant
wireless-tools
if-up.d
wpasupplicant
mountnfs
ntp
ntpdate
postfix
interfaces

See also:

  • dirname - extract the directory name from a full path
  • cd - change directory
  • pwd - confirm the current directory you’re in

dirname - extract the directory name from a full path

dirname is a very simple but useful Unix command which is used mostly in shell scripting. Taking a full path to a file as a parameter, it then stips the filename off and returns you just the directory name.

How to use dirname command

This is how dirname is invoked:

ubuntu$ dirname /etc/network/if-down.d/postfix
/etc/network/if-down.d

dirname in shell scripting

The obvious use of dirname command is shown below. This script, based on the full path to a file, prints the parent directory name and a list of all the files in this directory:

#!/bin/bash
FILE=$1
DIR=`dirname $FILE`
FILES=`ls $DIR`

echo "Filename specified: $FILE"
echo "Parent directory: $DIR"

for f in $FILES; do
echo "- $f"
done

See also:

  • basename - strip directory and suffix from a full path to a fil
  • cd - change directory
  • pwd - confirm the current directory you’re in

			

rmdir - remove empty directories

rmdir is one of the basic unix commands, which serves a sole purpose of removing empty directories. You may need this kind of functionality to attempt removing directories, and be sure that any files still existing in them will be safe. For removing any directory irregardless of any files in it, you should use the rm command.

To demonstrate how rmdir works, let's create two directories and two files in them:

ubuntu$ mkdir -p /tmp/dir1/dir2
ubuntu$ touch /tmp/dir1/file1
ubuntu$ touch /tmp/dir1/dir2/file2

This gives us the following file and directory structure:

ubuntu$ find /tmp/dir1
/tmp/dir1
/tmp/dir1/dir2
/tmp/dir1/dir2/file2
/tmp/dir1/file1

So, we have /tmp/dir1 directory, which contains a file1 file and a dir2 directory. /tmp/dir1/dir2 contains another file, called file2.

Basic rmdir usage

The simplest way to remove an empty directory is to run rmdir and supply the desired directory name as a command line parameter:

ubuntu$ rmdir /tmp/dir1/dir2
rmdir: `/tmp/dir1/dir2′: Directory not empty

In our example, we got the error because dir2 contains a file2 file, so it cannot be removed until the file exists.

Now, if we remove the file2 in dir2 directory, rmdir will happily destroy dir2 if we try again:

ubuntu$ rm /tmp/dir1/dir2/file1
ubuntu$ rmdir /tmp/dir1/dir2

Cascade directory removal with mkdir

If you want, you can attempt to do a cascade directory removal - if removing a specified directory succeeds, rmdir will try to remove its parent directory, if it's empty, and move up the directory tree until it meets a directory which isn't empty or which your use doesn't have permission to remove.

This kind of directory removal is achieved using rmdir -p option. If we recreate the dir2 directory under dir1 from our initial setup, you can see how rmdir will remove dir2 and then attempt to remove dir1, its parent directory:

ubuntu$ mkdir /tmp/dir1/dir2
ubuntu$ rmdir -p /tmp/dir1/dir2
rmdir: `/tmp/dir1′: Directory not empty

Now, the /tmp/dir1 removal is failed because it has file1 file left it it. So if we remove it and recreate the empty dir2, rmdir -p will successfully remove both directories.

First, let's prepare our 2 empty directories:

ubuntu$ rm /tmp/dir1/file1
ubuntu$ mkdir /tmp/dir1/dir2

This is how we double-check it's only dir1 with dir2 subdirectory:

ubuntu$ find /tmp/dir1
/tmp/dir1
/tmp/dir1/dir2

And now let's see how rmdir -p manages to remove both and even attempt to remove /tmp, cause it's the parent of /tmp/dir1:

ubuntu$ rmdir -p /tmp/dir1/dir2
rmdir: `/tmp': Permission denied

As usual, unix find command can testify that there's no /tmp/dir1 directory anymore:

ubuntu$ find /tmp/dir1
find: /tmp/dir1: No such file or directory

See also:

tune2fs - adjust tunable filesystem parameters

tune2fs command is one of the advanced unix commands which allows you to adjust various tunable parameters of the ext2/ext3 filesystems. Naturally, it also helps you confirm the existing parameters configured for your filesystems.

Confirm current filesystem parameters with tune2fs

The tunefs -l command will show you all the information contained in a filesystem's superblock. Here's how it typically looks:

ubuntu# tune2fs -l /dev/sda1
tune2fs 1.40-WIP (14-Nov-2006)
Filesystem volume name:   <none>
Last mounted on:          <not available>
Filesystem UUID:          d2ff8a06-74b7-4877-9d37-1873414e25b3
Filesystem magic number:  0xEF53
Filesystem revision #:    1 (dynamic)
Filesystem features:      has_journal filetype needs_recovery sparse_super
Default mount options:    (none)
Filesystem state:         clean
Errors behavior:          Continue
Filesystem OS type:       Linux
Inode count:              2490368
Block count:              4980736
Reserved block count:     249036
Free blocks:              3417990
Free inodes:              2401957
First block:              0
Block size:               4096
Fragment size:            4096
Blocks per group:         32768
Fragments per group:      32768
Inodes per group:         16384
Inode blocks per group:   512
Filesystem created:       Wed Sep 26 02:30:22 2007
Last mount time:          Tue Apr  1 00:17:16 2008
Last write time:          Tue Apr  1 00:17:16 2008
Mount count:              1
Maximum mount count:      29
Last checked:             Tue Apr  1 00:16:22 2008
Check interval:           15552000 (6 months)
Next check after:         Sun Sep 28 00:16:22 2008
Reserved blocks uid:      0 (user root)
Reserved blocks gid:      0 (group root)
First inode:              11
Inode size:               128
Journal inode:            8
Default directory hash:   tea
Directory Hash Seed:      c0c5742c-980a-49b2-ae0b-4e96895376b6
Journal backup:           inode blocks

Reserved space on a Unix filesystem

By default, every filesystem in Unix has some space reserved for the superuser (root). This means that no regular Unix user can fill your filesystem up to 100%, and so it's always going to have enough free space to continue normal function.

As a standard, each filesystem has 5% of space reserved in this way. If you look at the above output, you may notice the following lines there, which regulate the space reservation:

Reserved block count: 249036
Reserved blocks uid: 0 (user root)
Reserved blocks gid: 0 (group root)

Compared to the overall filesystem block count:

Block count: 4980736

this 249036 reserve is exactly 5%. The uid and gid confirm the Unix user id and Unix group id of the user who will be allowed to tap into the reserved space. As I said earlier, it's root.

If you have root access on your system, you can alter this reserved space allocation for any filesystem using tune2fs -m parameter, by specifying the percentage of the space to be reserved.

Here's how we change the default reserve to be 6% of the overall filesystem size:

ubuntu# tune2fs -m 6 /dev/sda1
tune2fs 1.40-WIP (14-Nov-2006)
Setting reserved blocks percentage to 6% (298844 blocks)

And here we change it back. Note how the number of block corresponding to 5% is exactly the figure we've seen earlier - 249036 blocks:

ubuntu# tune2fs -m 5 /dev/sda1
tune2fs 1.40-WIP (14-Nov-2006)
Setting reserved blocks percentage to 5% (249036 blocks)

Default block size for a filesystem

If you ever want to confirm the block size of any filesystem, tune2fs will help you do just that:

ubuntu# tune2fs -l /dev/sda1 | grep Block
Block count:              4980736
Block size:               4096
Blocks per group:         32768

From this example, you can see that the default block size for the filesystem on /dev/sda1 partition is 4096 bytes, or 4k. That's the default block size for ext3 filesystem.

ln - make links and symlinks between files or directories

ln is a Unix command for linking files or directories to each other. Essentially, it creates new files with the names you specify, and refer them to already existing files or directories. When you run any Unix command against a symlink, it is first resolved (the original file it points to is confirmed) and the Unix command works with that file to produce desired outcome.

Two types of linking files and directories

There are two common approaches to link a file or directory in Unix: soft linking and hard linking. Soft links are also called symlinks (symbolic links).

What is a soft link?

Soft link (also referred to as symlink - short for symbolic link) is a special type of file in Unix, which references another file or directory. Symlink contains the name for another file and contains no actual data. To most commands, symlinks look like a regular file, but all the operations (like reading from a file) are referred to the file the symlink points to.

When you remove a soft link, you simply remove one of the pointers to the real file. When you remove the original file a soft link points to, your data is lost. Even though your soft link will still exist, it will be pointing to the non-existent file and will therefore be useless (it will probably have to be removed as well).

What is a hard link?

Hard link is a pointer to physical data. Effectively, all standard files are hard links, because they ultimately create an association between a file name and a physical data which corresponds to each file.

In Unix, you can create as many hard links to a file as you like, and there is even a special counter for such references. When you're using the long format of an ls command, you can see this counter.

When you remove a hard link, you decrease this link counter for a data on your storage. If you remove the original file, the data will not be lost as long as there's at least one hard link pointing to it.

Creating soft links (symlinks) with ln

Let's start with a really simple example. We create a text file, and then use soft link to reference it.

This shows how the file is created. It's called file1, and has a line of text data in it which we confirm using cat command:

ubuntu$ echo "Text file #1″ > file1
ubuntu$ cat file1
Text file #1

Now let's use ln command to create a soft link. The newly created symlink will be a file called file2, and ls command will show you that it points to file1:

ubuntu$ ls -l file2
lrwxrwxrwx 1 root root 5 Mar 31 03:54 file2 -> file1

If you try accessing the file2, you will ultimately access file1, that's why the following example shows you the contents of file1:

ubuntu$ cat file2
Text file #1

Now, if you remove file1, this will make file2 symlink invalid, and any attempts to use it will return a "file not found" type of error:

ubuntu$ rm file1
ubuntu$ cat file2
cat: file2: No such file or directory

Creating hard links with ln

Now, let's look at creation of hard links in Unix. For this example, we'll recreate the file1:

ubuntu$ echo "Text file #1″ > file1
ubuntu$ cat file1
Text file #1

If you use ls to look at file1, you can see that the link counter (second field from the left) is set to 1 - which means that there is only one file name pointing to the data with our "Text file #1″ text:

ubuntu$ ls -l file1
-rw-r–r– 1 root root 13 Mar 31 06:18 file1

And now we use ln command to create a hard link called file3, which points to the same data as file1:

ubuntu$ ln file1 file3

If we use ls command once again, you can see that the link counter has been increased and is now 2:

ubuntu$ ls -l file1 file3
-rw-r–r– 2 root root 13 Mar 31 06:18 file1
-rw-r–r– 2 root root 13 Mar 31 06:18 file3

Notice, how the file1 and file3 files look like absolutely normal files, and there's nothing showing a logical link between them.

To confirm that both filenames are actually referring to the same area on the disk, you can use -i option for the ls command, which will show you an i-node value.

i-nodes are data structures of a filesystem used to store all the important properties of each file: size, owner's user id and group id, access permission and more. The important thing is that each named data area on your disk must have an inode, and when you create a new data file this means creating an i-node. But when you're using hard links, you're effectively creating filesystem directory entry, which references an already existing data, so the hard link gets the same i-node number pointing to the same data.

ubuntu$ ls -il file1 file3
655566 -rw-r–r– 2 root root 13 Mar 31 06:18 file1
655566 -rw-r–r– 2 root root 13 Mar 31 06:18 file3

The first number in each line of the output is the i-node number, and since we're referencing the same data, the i-node numbers are also the same.

See also: