This modification to the cd command adds automatic directory intelligence:
cd() {
builtin cd "$@" || return
# 1. Display info file in Magenta
if [[ -f ".dirinfo" ]]; then
echo -e "\e[35m$(cat .dirinfo)\e[0m"
fi
# 2. Execute file ONLY if owned by you and executable
# BEWARE: Potential security issue if enabled!
# if [[ -x ".direxecute" ]]; then
# if [[ "$(stat -c "%u" .direxecute)" -eq "$UID" ]]; then
# ./.direxecute
# else
# echo -e "\e[31mSecurity: Skipping .direxecute (Wrong Owner)\e[0m"
# fi
# fi
}
A robust directory lister built to handle the unique challenges of WSL and large-scale file management. Features include 3-second safety timeouts, sequence grouping, and space-safe filename parsing.
#!/usr/bin/perl # fileinfo=The Directory Archeologist - Master Version (v2026.03.02) use strict; use warnings; use File::Basename; use Getopt::Long; # --- 1. SETUP & FLAGS --- my $show_all = 0; my $help = 0; my $group_mode = 0; my $script_name = basename($0); GetOptions( 'all|a' => \$show_all, 'help|h' => \$help, 'group|g' => \$group_mode ) or exit 1; if ($help) { print_help(); exit; } my $term_width = `tput cols` || 80; my @args = @ARGV; my $target_dir = "."; my @ls_flags = qw/-lh --color=always --group-directories-first/; if (@args == 0) { push @args, "."; } elsif (@args == 1 && -d $args[0]) { $target_dir = $args[0]; $target_dir =~ s|/$||; } else { push @ls_flags, "-d"; } # --- 2. EXECUTE LS --- my $cmd_str = "ls " . join(' ', @ls_flags, ($show_all ? "-a" : ()), map { "\"$_\"" } @args) . " 2>&1"; open(my $ls_fh, "-|", $cmd_str) or die "Could not run ls: $!"; my @ls_lines = <$ls_fh>; close($ls_fh); # --- 3. PASS 1: PARSING --- my %groups; my @order; foreach my $line (@ls_lines) { chomp $line; next if $line =~ /^total/ || $line =~ /:$/; if ($line =~ /ls: cannot access '(.+)': No such file or directory/) { my $bad_file = $1; push @order, "ERR_$bad_file"; $groups{"ERR_$bad_file"} = { files => [{ name => $bad_file, clean => $bad_file, is_err => 1, bytes => 0, colored => $bad_file }], month => "---", day => "--", year => "----" }; next; } if ($line =~ /^(\S+)\s+(\d+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(.+)$/) { my @m = ($1, $2, $3, $4, $5, $6, $7, $8, $9); my $colored_name = $m[8]; my $clean_name = $colored_name; $clean_name =~ s/\x1b\[[0-9;]*m//g; $clean_name =~ s/\s+->\s+.*$//; $colored_name =~ s/\s+->\s+.*$//; my $actual_name = $clean_name; $actual_name =~ s/^'//; $actual_name =~ s/'$//; next if $actual_name eq '.' || $actual_name eq '..'; my $key = "SINGLE_$actual_name"; my $num = undef; if ($group_mode && $actual_name =~ /^(.*?)(\d+)(\D*)$/) { $key = "GRP_$1_LEN" . length($2) . "_$3"; $num = $2; } if (!$groups{$key}) { push @order, $key; $groups{$key} = { files => [], month => $m[5], day => $m[6], year => $m[7] }; } my $bytes = parse_to_bytes($m[4]); push @{$groups{$key}->{files}}, { name => $actual_name, num => $num, line => $line, bytes => $bytes, clean => $clean_name, colored => $colored_name }; } } # --- 4. PASS 2: GROUPING --- my @print_list; my $max_name_len = 0; my $max_size_len = 0; foreach my $key (@order) { my $g = $groups{$key}; my @sorted = sort { ($a->{num}||0) <=> ($b->{num}||0) } @{$g->{files}}; my @sub_ranges; my $range_idx = 0; if (defined $sorted[0]->{num} && @sorted > 1) { for (my $i = 1; $i <= $#sorted; $i++) { if ($sorted[$i]->{num} != $sorted[$i-1]->{num} + 1) { push @sub_ranges, [ @sorted[$range_idx .. $i-1] ]; $range_idx = $i; } } push @sub_ranges, [ @sorted[$range_idx .. $#sorted] ]; } else { foreach my $f (@sorted) { push @sub_ranges, [$f]; } } foreach my $range (@sub_ranges) { my @files = @{$range}; my $total_bytes = 0; $total_bytes += $_->{bytes} for @files; my $s_str = format_bytes($total_bytes); my $display_name = (@files > 1) ? "$files[0]->{name} - $files[-1]->{name} (" . scalar(@files) . " files)" : $files[0]->{clean}; $max_name_len = length($display_name) if length($display_name) > $max_name_len; $max_size_len = length($s_str) if length($s_str) > $max_size_len; my $orig_name = $files[0]->{name}; my $full_path = ($target_dir ne "." && ! -e $orig_name && ! -l $orig_name) ? "$target_dir/$orig_name" : $orig_name; my $priority = (-d $full_path) ? 0 : 1; push @print_list, { meta => [$s_str, $g->{month}, $g->{day}, $g->{year}], display => $display_name, is_group => (@files > 1), colored => $files[0]->{colored}, path => $orig_name, full_path => $full_path, is_err => $files[0]->{is_err} || 0, priority => $priority }; } } @print_list = sort { $a->{priority} <=> $b->{priority} || lc($a->{display}) cmp lc($b->{display}) } @print_list; # --- 5. PASS 3: PRINT --- $max_name_len += 2; my $name_limit = int($term_width * 0.40); $max_name_len = $name_limit if $max_name_len > $name_limit; foreach my $p (@print_list) { my $full_path = $p->{full_path}; my ($desc, $desc_color) = ("", "\e[90m"); my $size_display = $p->{meta}->[0]; my $colored_name = $p->{is_group} ? "\e[1;33m$p->{display}\e[0m" : $p->{colored}; if ($p->{is_err}) { $desc = "!! FILE MISSING OR INACCESSIBLE"; $desc_color = "\e[1;31m"; $colored_name = "\e[1;31m$p->{display}\e[0m"; } elsif (-l $full_path) { my $target = readlink($full_path); my $exists = -e $full_path; my $note = ""; if (-f "$full_path/.dirinfo") { if (open my $nfh, '<', "$full_path/.dirinfo") { $note = <$nfh>; chomp $note; close $nfh; } } my $note_part = $note ? " [ $note ]" : ""; if (! $exists) { $desc = "!! BROKEN symlink to $target$note_part"; $desc_color = "\e[1;31m"; $colored_name = "\e[1;31m$p->{display}\e[0m"; } else { $desc = "symlink to $target$note_part"; $desc_color = "\e[36m"; } } elsif (-d $full_path) { $desc = get_dir_stats($full_path); $desc_color = "\e[35m"; } else { $desc = get_file_desc($full_path); } my $meta = sprintf("%${max_size_len}s %s %2s %5s", $size_display, $p->{meta}->[1], $p->{meta}->[2], $p->{meta}->[3]); $desc =~ s/^\#\s*//; my $prefix_width = length($meta) + $max_name_len + 3; my $max_desc_width = $term_width - $prefix_width - 1; if (length($desc) > $max_desc_width) { $desc = substr($desc, 0, $max_desc_width - 3) . "..."; } my $pad_len = $max_name_len - length($p->{display}); $pad_len = 1 if $pad_len < 1; my $padding = " " x $pad_len; printf "%s %s%s %s%s\e[0m\n", $meta, $colored_name, $padding, $desc_color, $desc; } # --- SUBROUTINES --- sub parse_to_bytes { my $val_str = shift || "0"; my ($val, $unit) = ($val_str =~ /^([\d\.]+)([KMG]?)$/); my $b = $val || 0; if ($unit) { if ($unit eq 'K') { $b *= 1024; } elsif ($unit eq 'M') { $b *= 1024 * 1024; } elsif ($unit eq 'G') { $b *= 1024 * 1024 * 1024; } } return $b; } sub format_bytes { my $b = shift; return "0" if $b == 0; if ($b < 1024) { return $b; } if ($b < 1024 * 1024) { return sprintf("%.1fK", $b/1024); } if ($b < 1024 * 1024 * 1024) { return sprintf("%.1fM", $b/(1024*1024)); } return sprintf("%.1fG", $b/(1024*1024*1024)); } sub get_dir_stats { my $dir = shift; my $cache = "$dir/.li_cache"; my $mtime = (stat($dir))[9] || 0; if (-f $cache) { if (open my $fh, '<', $cache) { my $line = <$fh>; close $fh; if ($line && $line =~ /^$mtime (.*)/) { return $1; } } } my $note = ""; if (-f "$dir/.dirinfo") { if (open my $nfh, '<', "$dir/.dirinfo") { $note = <$nfh>; chomp $note; close $nfh; } } if (-l $dir) { return $note ? "[ $note ]" : ""; } my $res; eval { local $SIG{ALRM} = sub { die "timeout\n" }; alarm 3; my $visible_files = `find "$dir" -maxdepth 1 -type f ! -name ".*" 2>/dev/null | wc -l` - 0; my $hidden_all = `find "$dir" -maxdepth 1 -type f -name ".*" 2>/dev/null | wc -l` - 0; foreach my $metafile (qw/.fileinfo .dirinfo .li_cache/) { $hidden_all-- if -f "$dir/$metafile"; } my $sub_directories = `find "$dir" -maxdepth 1 -type d 2>/dev/null | wc -l` - 1; my $total_size = `du -sh "$dir" 2>/dev/null | cut -f1`; chomp $total_size; my $note_part = $note ? " - $note" : ""; my $h_str = ($hidden_all > 0) ? " ($hidden_all hidden)" : ""; my $f_str = ($visible_files > 0) ? $visible_files . " file" . ($visible_files == 1 ? "" : "s") . $h_str : ($hidden_all > 0 ? "$hidden_all hidden files" : ""); my $s_str = ($sub_directories > 0) ? ($f_str ne "" ? " & " : "") . $sub_directories . " sub" . ($sub_directories == 1 ? "" : "s") : ""; if ($f_str eq "" && $s_str eq "") { $res = "[ empty dir$note_part ]"; } else { $res = "[ $f_str$s_str in $total_size$note_part ]"; } alarm 0; }; if ($@) { my $note_part = $note ? " - $note" : ""; $res = ($@ eq "timeout\n") ? "[ SCAN TIMEOUT$note_part ]" : "[ SCAN ERROR$note_part ]"; } if (-w $dir && $res !~ /TIMEOUT|ERROR/) { if (open my $cfh, '>', $cache) { print $cfh "$mtime $res"; close $cfh; } } return $res; } sub get_file_desc { my $file_path = shift; my $file_name = basename($file_path); my $parent_dir = dirname($file_path); if (-T $file_path && open(my $fh, '<', $file_path)) { while (<$fh>) { if (/fileinfo=(.*)/) { my $found = $1; close $fh; return "# $found"; } last if $. > 10; } close $fh; } my $dot_fileinfo = "$parent_dir/.fileinfo"; if (-f $dot_fileinfo) { if (open my $mfh, '<', $dot_fileinfo) { while (<$mfh>) { next if /^\s*#/ || ! /=/; my ($pattern, $description) = split('=', $_, 2); chomp $description; $pattern =~ s/\*/.*/g; if ($file_name =~ /^$pattern$/) { close $mfh; return "# $description"; } } close $mfh; } } my $file_type = `file -b "$file_path" 2>/dev/null`; chomp $file_type; return $file_type || "unknown file type"; } sub print_help { print <<EOF; Usage: $script_name [options] [path] Options: -a, --all Show hidden files -g, --group Consolidate numbered sequences -h, --help Show this help message EOF }