1+ # implement-shell-tools/ls/ls.py
12import argparse
23import os
4+ import sys
5+ import shutil
6+ import math
7+
8+ def print_columns (items , force_single_column = False ):
9+ """Print items in columns unless -1 is passed or output is not a tty."""
10+ if force_single_column or not sys .stdout .isatty ():
11+ for item in items :
12+ print (item )
13+ return
14+
15+ # Get terminal width
16+ term_width = shutil .get_terminal_size ((80 , 20 )).columns
17+
18+ if not items :
19+ return
20+
21+ # Longest filename length + spacing
22+ max_len = max (len (f ) for f in items ) + 2
23+ cols = max (1 , term_width // max_len )
24+ rows = math .ceil (len (items ) / cols )
25+
26+ for r in range (rows ):
27+ row_items = []
28+ for c in range (cols ):
29+ i = c * rows + r
30+ if i < len (items ):
31+ row_items .append (items [i ].ljust (max_len ))
32+ print ("" .join (row_items ).rstrip ())
333
4- # implement-shell-tools/ls/ls.py
534def main ():
635 parser = argparse .ArgumentParser (
736 prog = "ls" ,
837 description = "Implements a simple version of the 'ls' command to list files in a directory."
938 )
1039
11- parser .add_argument ("-1" , help = "" , action = "store_true" )
12- parser .add_argument ("-a" , help = "" , action = "store_true" )
40+ parser .add_argument ("-1" , help = "List one file per line " , action = "store_true" )
41+ parser .add_argument ("-a" , help = "Include hidden files " , action = "store_true" )
1342 parser .add_argument ("directory" , nargs = "?" , default = "." , help = "The directory to search" )
1443
1544 args = parser .parse_args ()
1645
1746 try :
18- files = os .listdir (args .directory )
47+ if os .path .isdir (args .directory ):
48+ files = os .listdir (args .directory )
1949
20- if not args .a :
21- files = [f for f in files if not f .startswith ("." )]
22-
23- files = sorted (files )
50+ if not args .a :
51+ files = [f for f in files if not f .startswith ("." )]
52+
53+ files = sorted (files )
2454
25- for f in files :
26- print (f )
55+ print_columns (files , force_single_column = args .__dict__ ["1" ])
56+ else :
57+ # If it's a file, just print the name
58+ print (args .directory )
2759
2860 except FileNotFoundError :
29- print (f"ls: { args .directory } : No such file or directory" )
30- except NotADirectoryError :
31- print (args .directory )
61+ print (f"ls: { args .directory } : No such file or directory" , file = sys .stderr )
3262 except Exception as e :
33- print (f"ls: { args .directory } : { e } " )
63+ print (f"ls: { args .directory } : { e } " , file = sys . stderr )
3464
3565if __name__ == "__main__" :
3666 main ()
0 commit comments