#!/bin/bash print_usage() { echo "Usage:" echo " collect [-o] [-m] [-i] range file" echo " Examples:" echo " collect 1,3 file.txt # Copy lines to clipboard" echo " collect -o 1,3 file.txt # Print lines to stdout" echo " collect -m 1,3:5,7:9,9 file.txt # Multiple ranges, separated by ':'" echo " collect -i 1,3 file.txt # Inverse selection (all except lines 1-3)" exit 1 } validate_range() { local range=$1 local file=$2 local total_lines=$(wc -l < "$file") if ! [[ $range =~ ^[0-9]+(,[0-9]+)?$ ]]; then echo "Error: Invalid range format '$range'. Expected format: n or n,m" return 1 fi IFS=',' read -r start end <<< "$range" if [ -z "$end" ]; then end=$start fi if [ "$start" -gt "$end" ]; then echo "Error: Invalid range '$range'. Start line must be less than or equal to end line." return 1 fi if [ "$start" -eq 0 ] || [ "$end" -gt "$total_lines" ]; then echo "Error: Range '$range' is out of bounds. File has $total_lines lines." return 1 fi return 0 } process_range() { local range=$1 local file=$2 local inverse=$3 local total_lines=$(wc -l < "$file") if [ "$inverse" = true ]; then IFS=',' read -r start end <<< "$range" if [ -z "$end" ]; then end=$start fi if [ "$start" -gt 1 ]; then sed -n "1,$((start-1))p" "$file" fi if [ "$end" -lt "$total_lines" ]; then sed -n "$((end+1)),$((total_lines))p" "$file" fi else sed -n "${range}p" "$file" fi } if [ "$#" -lt 2 ]; then print_usage fi output_mode=false multi_range=false inverse_mode=false while getopts "omi" opt; do case ${opt} in o ) output_mode=true ;; m ) multi_range=true ;; i ) inverse_mode=true ;; \? ) print_usage ;; esac done shift $((OPTIND -1)) if [ "$#" -ne 2 ]; then print_usage fi ranges=$1 file=$2 if [ ! -f "$file" ]; then echo "Error: File '$file' does not exist." exit 1 fi if [ "$multi_range" = true ]; then IFS=':' read -ra RANGE_ARRAY <<< "$ranges" for range in "${RANGE_ARRAY[@]}"; do if ! validate_range "$range" "$file"; then exit 1 fi done else if ! validate_range "$ranges" "$file"; then exit 1 fi fi if [ "$output_mode" = false ]; then if ! command -v xclip &> /dev/null; then echo "Error: xclip could not be found. Please install xclip." exit 1 fi fi if [ "$inverse_mode" = true ] && [ "$multi_range" = true ]; then echo "Error: Inverse selection (-i) cannot be used with multiple ranges (-m)" exit 1 fi temp_file=$(mktemp) if [ "$multi_range" = true ]; then for range in "${RANGE_ARRAY[@]}"; do process_range "$range" "$file" false >> "$temp_file" done else process_range "$ranges" "$file" "$inverse_mode" >> "$temp_file" fi if [ "$output_mode" = true ]; then cat "$temp_file" else cat "$temp_file" | xclip -selection clipboard if [ "$inverse_mode" = true ]; then echo "All lines except $ranges from file '$file' have been copied to the clipboard." else echo "Lines $ranges from file '$file' have been copied to the clipboard." fi fi rm "$temp_file"