How to Skip First Line
Quick Answer: Skip First Line in Bash
To skip the first line when processing a file in Bash, use tail -n +2 filename. For a loop, use read -r first to consume the header, then loop: read -r header; while read -r line; do ....
Quick Comparison: Header Skipping Methods
| Method | Syntax | Best For | Complexity |
|---|---|---|---|
| tail -n +2 | tail -n +2 file | Simple skip | Very simple |
| read first | read header; while read... | Loops | Simple |
| sed 1d | sed 1d file | Piping | Simple |
| awk NR>1 | awk 'NR>1' file | Complex logic | Moderate |
| skip/head | head -n -1 file | Partial skip | Moderate |
Bottom line: Use tail -n +2 for piping, use read for loops.
Overview
Many text files and data sources start with header lines that describe the columns or content but shouldn’t be processed as data. Whether you’re working with CSV files, log files, or command output, you’ll frequently need to skip the first line (or first N lines). This tutorial covers multiple efficient methods to skip header lines when processing files in Bash.
Method 1: Using tail Command
The tail command shows the last N lines of a file. By using -n +2, you skip the first line and process the rest:
# Skip first line and process rest
tail -n +2 filename.txt
# Skip first 3 lines
tail -n +4 filename.txt
# Example:
tail -n +2 data.csv | while read line; do
echo "Processing: $line"
done
Example output:
# Input file (data.csv):
# Name,Age,City
# John,30,New York
# Jane,25,Los Angeles
# Bob,35,Chicago
$ tail -n +2 data.csv
John,30,New York
Jane,25,Los Angeles
Bob,35,Chicago
Method 2: Using read in while Loop
Skip the header by reading the first line separately before processing:
# Read header separately, then process data
read -r header < filename.txt
echo "Header: $header"
# Process remaining lines
while IFS= read -r line; do
echo "Data: $line"
done < filename.txt
Or more explicitly:
while IFS= read -r line; do
echo "Processing: $line"
done < <(tail -n +2 filename.txt)
Method 3: Using sed
The sed command can delete the first line before processing:
# Delete first line and process rest
sed '1d' filename.txt
# Delete first 3 lines
sed '1,3d' filename.txt
# Skip and process
sed '1d' data.csv | while read line; do
echo "Processing: $line"
done
Example:
$ sed '1d' data.csv
John,30,New York
Jane,25,Los Angeles
Bob,35,Chicago
Method 4: Using awk
awk can easily skip header with the NR>1 condition:
# Process all lines except first
awk 'NR>1' filename.txt
# Skip first line and process specific fields
awk 'NR>1 {print $1, $2}' filename.txt
# With field separator for CSV
awk -F',' 'NR>1 {print $1}' data.csv
Example:
$ awk 'NR>1' data.csv
John,30,New York
Jane,25,Los Angeles
Bob,35,Chicago
# Extract just names
$ awk -F',' 'NR>1 {print $1}' data.csv
John
Jane
Bob
Practical Examples
Example 1: Process CSV File Skipping Header
#!/bin/bash
csv_file="$1"
if [ ! -f "$csv_file" ]; then
echo "File not found"
exit 1
fi
# Read CSV and process each line
tail -n +2 "$csv_file" | while IFS=',' read -r name age city; do
echo "Name: $name, Age: $age, City: $city"
done
Input (employees.csv):
Name,Age,City
John,30,New York
Jane,25,Los Angeles
Output:
$ bash script.sh employees.csv
Name: John, Age: 30, City: New York
Name: Jane, Age: 25, City: Los Angeles
Example 2: Count Lines Excluding Header
#!/bin/bash
file="$1"
# Count lines excluding header
count=$(tail -n +2 "$file" | wc -l)
echo "Total records (excluding header): $count"
Output:
$ bash script.sh data.csv
Total records (excluding header): 5
Example 3: Process Multiple Files Skipping Headers
#!/bin/bash
# Process multiple CSV files, skipping headers
for csvfile in *.csv; do
[ -f "$csvfile" ] || continue
echo "Processing: $csvfile"
# Skip header, process data
awk -F',' 'NR>1 {print "User: " $1, "Email: " $3}' "$csvfile"
done
Example 4: Merge Multiple Files, Remove Duplicate Headers
#!/bin/bash
# Merge multiple CSV files keeping header from first file only
output_file="merged.csv"
# Process first file (include header)
cat "$1" > "$output_file"
# Process remaining files (skip headers)
shift
for file in "$@"; do
tail -n +2 "$file" >> "$output_file"
done
echo "Merged into: $output_file"
Example 5: Process Log File Skipping Metadata
#!/bin/bash
log_file="$1"
skip_lines=${2:-3} # Default skip 3 lines
echo "Skipping first $skip_lines lines of $log_file"
# Skip metadata lines and process log entries
tail -n +$((skip_lines + 1)) "$log_file" | while IFS= read -r line; do
# Process each log line
timestamp=$(echo "$line" | awk '{print $1, $2}')
level=$(echo "$line" | awk '{print $3}')
message=$(echo "$line" | cut -d' ' -f4-)
echo "[$timestamp] $level: $message"
done
Example 6: Function to Process File Without Header
#!/bin/bash
# Reusable function to skip header
process_without_header() {
local file="$1"
local skip_count="${2:-1}"
if [ ! -f "$file" ]; then
echo "Error: File not found"
return 1
fi
tail -n +$((skip_count + 1)) "$file"
}
# Usage
process_without_header "data.csv" 1 | while IFS=',' read -r field1 field2 field3; do
echo "Processing: $field1"
done
Performance Comparison
For skipping headers in large files:
| Method | Speed | Memory | Best For |
|---|---|---|---|
| tail -n +2 | Very Fast | Low | Simple, one-liners |
| awk ‘NR>1’ | Very Fast | Low | Complex processing |
| sed ‘1d’ | Fast | Low | Piping, streaming |
| read in loop | Medium | Low | Small files |
Best choice: Use tail -n +2 for simplicity, awk 'NR>1' for complex processing.
Handling Different Scenarios
Skip Variable Number of Lines
#!/bin/bash
file="$1"
skip_lines="${2:-1}"
echo "Skipping $skip_lines lines..."
tail -n +$((skip_lines + 1)) "$file"
Skip to Specific Line Number
# Skip to line 10
tail -n +10 filename.txt
# Process lines 5-15
sed -n '5,15p' filename.txt
Skip Based on Pattern
# Skip lines that start with '#' (comments)
grep -v '^#' filename.txt
# Skip empty lines
grep -v '^$' filename.txt
# Skip both empty and comment lines
grep -v '^[#[:space:]]*$' filename.txt
Key Points
- Use
tail -n +2to skip first line efficiently - Use
awk 'NR>1'for complex processing after skipping - Use
sed '1d'when piping data through multiple commands - Remember that line counting starts at 1, not 0
- Always check file existence before processing
- Consider performance with very large files
Quick Reference
# Skip first line
tail -n +2 file.txt
# Skip first N lines
tail -n +$((N+1)) file.txt
# Skip with awk
awk 'NR>1' file.txt
# Skip with sed
sed '1d' file.txt
# Skip in CSV loop
while IFS=',' read -r f1 f2 f3; do
echo "$f1 $f2 $f3"
done < <(tail -n +2 file.csv)
Recommended Pattern
#!/bin/bash
file="$1"
# Method 1: Simple one-liner with tail
tail -n +2 "$file" | while IFS=',' read -r col1 col2 col3; do
echo "Processing: $col1"
done
# Method 2: With file validation
if [ -f "$file" ]; then
awk -F',' 'NR>1 {print $1, $2}' "$file"
else
echo "Error: File not found"
exit 1
fi