UNIX File System: An Overview

A file in UNIX is essentially a collection of data, whether it be text, binary, or structured information. The UNIX file system provides various commands for examining and managing files. This post covers some fundamental commands used to inspect and navigate files efficiently.

Viewing File Content with od

The od (octal dump) command displays a file’s contents in different formats, which is useful for inspecting non-text files. Some commonly used options include:

  • -c: Interprets bytes as characters.
  • -b: Prints bytes as octal numbers.
  • No option: Dumps the file in 16-bit words (default).

Example:

$ od -c example.txt   # Show file content as characters
$ od -b example.txt   # Show file content in octal format
$ od example.txt      # Default output (16-bit words)

Identifying File Types with file

The file command determines a file’s type by inspecting its contents rather than relying on extensions.

Example:

$ file example.txt
example.txt: ASCII text
$ file script.sh
script.sh: Bourne-Again shell script, UTF-8 Unicode text
$ file binary_file
binary_file: ELF 64-bit LSB executable, x86-64

Checking Disk Usage with du

The du (disk usage) command reports the disk space used by files and directories.

  • du: Shows disk usage of directories.
  • du -a: Includes files along with directories.
  • du -h: Displays sizes in a human-readable format.
  • du -a | grep filename: Filters output for a specific file.

Example:

$ du             # Show disk usage of directories
$ du -a          # Show disk usage of all files and directories
$ du -h          # Display sizes in human-readable format (e.g., KB, MB, GB)
$ du -a | grep example.txt  # Search for a specific file's usage

Understanding UNIX Directories

A UNIX directory consists of 16-byte chunks:

  • The first two bytes point to the administrative information.
  • The last 14 bytes contain the file name, padded with ASCII null characters (NUL).

Understanding this structure helps in low-level file system debugging and development.

Finding Files with find

The find command searches for files based on criteria like name, type, size, and modification time.

Basic usage:

$ find . -name "example.txt"    # Find a file named 'example.txt' in the current directory
$ find /home -type f -size +10M  # Find files larger than 10MB in /home
$ find /var/log -mtime -7         # Find files modified in the last 7 days in /var/log

Additional Useful Commands

  • ls -l: Lists files with detailed information.
  • stat filename: Displays detailed file metadata.
  • df -h: Shows available disk space in a human-readable format.

With these commands, managing and analyzing files in UNIX becomes efficient and insightful. Mastering them will help streamline system operations and troubleshooting.

Programming in C: Essential Points on Constants

Constants play a crucial role in C programming, providing fixed values that do not change during program execution. Here are some important points to remember when dealing with constants in C:

Integer Constants

  1. Long Constants: A long integer constant is written with an ‘L’ or ‘l’ suffix. For example: long num1 = 1234567697L; long num2 = 567874338l; // Avoid using 'l' (lowercase) as it can be confused with '1'
  2. Unsigned Constants: An unsigned integer constant is written with a ‘U’ or ‘u’ suffix: unsigned int positiveNum = 40000U;
  3. Unsigned Long Constants: These constants have both ‘U’ and ‘L’ suffixes: unsigned long bigPositiveNum = 123456789UL;

Floating-Point Constants

Floating-point constants must contain a decimal point, an exponent (e.g., 1e-1), or both. They are automatically treated as double unless explicitly declared otherwise:

double pi = 3.14159;
float gravity = 9.8F;
double smallValue = 1.23e-4;  // 1.23 × 10⁻⁴

Octal and Hexadecimal Representation

Integer values can be specified in decimal, octal, or hexadecimal notation:

int decimalNum = 31;  // Decimal
int octalNum = 031;   // Octal (leading 0 means octal, equivalent to 25 in decimal)
int hexNum = 0x1F;    // Hexadecimal (leading 0x means hex, equivalent to 31 in decimal)

Character and String Constants

  1. Character Constants: A character constant is essentially an integer representing the corresponding ASCII value. char ch = 'A'; // ASCII value is 65
  2. String Constants (String Literals): A string constant is a sequence of characters enclosed in double quotes. char greeting[] = "Hello, C!";

Constant Expressions

A constant expression is an expression that consists only of constants. Such expressions are evaluated at compile time.

#define PI 3.14159
const int maxValue = 100;
int area = 5 * 10; // Constant expression evaluated at compile-time

Constants in Control Flow Statements

  1. Switch Statements: Each case label must be associated with an integer constant or a constant expression. switch (choice) { case 1: printf("Option 1 selected\n"); break; case 2 + 1: // Constant expression printf("Option 3 selected\n"); break; default: printf("Invalid option\n"); }
  2. Continue Statement:
    • In while and do-while loops, continue immediately jumps to the condition check.
    • In for loops, it moves to the increment step.
    • It does not apply to switch statements.
    for (int i = 0; i < 5; i++) { if (i == 2) continue; // Skips printing '2' printf("%d ", i); } Output: 0 1 3 4

By keeping these fundamental points in mind, you can write cleaner and more efficient C programs.

Programming in C: Important Points on Operators

Operators play a crucial role in C programming, enabling efficient computations and manipulations. Here are some key points to remember about C operators:

1. Cast Operator Precedence

The cast operator () has the same high precedence as other unary operators like sizeof, !, &, *, +, and -. This means that type conversions occur before most binary operations.

Example:

#include <stdio.h>

int main() {
    int x = 10;
    int y = 3;
    double result = (double)x / y; // Casts x to double before division
    printf("%f\n", result); // Output: 3.333333
    return 0;
}

2. Increment and Decrement Operators

The increment (++) and decrement (--) operators can only be applied to variables, not to expressions or constants.

Invalid Example:

(int)10++; // Error: Cannot apply increment to a constant expression

Valid Example:

int a = 5;
a++; // Valid, modifies the variable

3. Bitwise Shift Operators

Bitwise shift operators (<<, >>) allow shifting bits left or right, typically used for performance optimizations or low-level programming.

Right Shift (>>)

The right shift operator moves bits to the right and discards excess bits. The behavior for signed integers is implementation-defined (logical or arithmetic shift).

Example:

#include <stdio.h>

int main() {
    int var = 32; // Binary: 00100000
    int shifted = var >> 2; // Binary: 00001000 (8 in decimal)
    printf("%d\n", shifted); // Output: 8
    return 0;
}

Here, var is shifted 2 positions to the right. The empty bit positions are filled with zeroes for unsigned integers.

Left Shift (<<)

The left shift operator moves bits to the left, filling the empty positions with zeros.

Example:

int b = 5;   // Binary: 00000101
int c = b << 3; // Binary: 00101000 (40 in decimal)
printf("%d\n", c); // Output: 40

4. Bitwise Operators and Integral Types

Bitwise operators (&, |, ^, ~, <<, >>) can only be used with integral types (such as int, char, long). They do not work with floating-point numbers (float, double).

Invalid Example:

float f = 5.5;
int result = f >> 1; // Error: Bitwise shift not allowed on floating-point numbers

Summary

  • The cast operator has the same precedence as other unary operators.
  • Increment (++) and decrement (--) apply only to variables, not expressions or constants.
  • Bitwise shift operators (>>, <<) operate only on integral types and cannot be used with floating-point numbers.
  • The behavior of right shift on negative numbers is implementation-dependent.

By keeping these rules in mind, you can avoid common pitfalls when working with operators in C.