Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
This repository was archived by the owner on Jan 23, 2019. It is now read-only.

Commit 717c64c

Browse files
author
js-d-coder
committed
first commit
0 parents commit 717c64c

File tree

3 files changed

+286
-0
lines changed

3 files changed

+286
-0
lines changed

‎LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2017 js-d-coder
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

‎README.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# lsi
2+
ls command alternative. Output is either cleanly formatted table or string of null terminated file names parseable by xargs command. Default behaviour is to show only non-hidden files (no directories) of directory passed or current directory if no directory is given in table format.
3+
4+
## Usage
5+
6+
usage: lsi [-h] [-x] [-n | -i | -a] [-d | -w] [-v] [FILE [FILE ...]]
7+
8+
ls command alternative. Output is either cleanly formatted table or string of
9+
null terminated file names parseable by xargs command. Default behaviour is to
10+
show only non-hidden files (no directories) of directory passed or current
11+
directory if no directory is given in table format.
12+
13+
positional arguments:
14+
FILE space separated list of any numbers of files and/or
15+
directories. If not given current directory will be
16+
assumed
17+
18+
optional arguments:
19+
-h, --help show this help message and exit
20+
-x, --xargs output will be string of null terminated file
21+
names.Can be used as input to other commands like
22+
xargs. Absense of this option makes output to be a
23+
table, which is default
24+
-n, --non-hidden show files (and directories with -w) with names that
25+
does not start with a dot. This is default
26+
-i, --hidden show files (and directories with -w) with names
27+
starting with a dot
28+
-a, --include-hidden show all files (and directories with -w), including
29+
hidden ones
30+
-d, --only-dir show directories only and not regular file
31+
-w, --include-dir show directories along with files. Can be used with
32+
option -n, -i or -a
33+
-v, --version output version information and exit
34+
35+
36+
## Examples
37+
38+
$ lsi
39+
'file20' 'file19' 'file18' 'file17' 'file16' 'file15' 'file14' 'file13' 'file12'
40+
'file11' 'file10' 'file9' 'file8' 'file7' 'file6' 'file5' 'file4' 'file3'
41+
'file2' 'file1'
42+
$ lsi -d
43+
'dir20/' 'dir19/' 'dir18/' 'dir17/' 'dir16/' 'dir15/' 'dir14/' 'dir13/' 'dir12/'
44+
'dir11/' 'dir10/' 'dir9/' 'dir8/' 'dir7/' 'dir6/' 'dir5/' 'dir4/' 'dir3/'
45+
'dir2/' 'dir1/'
46+
$ lsi -w
47+
'file20' 'file19' 'file18' 'file17' 'file16' 'file15' 'file14' 'file13' 'file12'
48+
'file11' 'file10' 'file9' 'file8' 'file7' 'file6' 'file5' 'file4' 'file3'
49+
'file2' 'file1' 'dir20/' 'dir19/' 'dir18/' 'dir17/' 'dir16/' 'dir15/' 'dir14/'
50+
'dir13/' 'dir12/' 'dir11/' 'dir10/' 'dir9/' 'dir8/' 'dir7/' 'dir6/' 'dir5/'
51+
'dir4/' 'dir3/' 'dir2/' 'dir1/'
52+
53+
[You should not parse the output of `ls` command, but **you can safely parse the output of `lsi`**](http://www.mywiki.wooledge.org/ParsingLs)
54+
55+
$ lsi -x | xargs -r0 cat

‎lsi

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
#!/usr/bin/env python3
2+
"""ls command alternative.
3+
Output is either cleanly formatted table or
4+
string of null terminated file names parseable by xargs command.
5+
Default behaviour is to show only non-hidden files (no directories) of
6+
directory passed or current directory if no directory is given in table format.
7+
Learn more by passing -h or --help option.
8+
NOTE: requires python v3+ (tested on v3.6); written for UNIX-like OS
9+
REAL Programmers don't need comments, for them the code itself is obvious,
10+
but if you aren't one of them, here you go.
11+
"""
12+
13+
14+
import argparse
15+
import os
16+
import sys
17+
18+
# get size of the terminal, useful if output is in table format
19+
terminalRowSize, terminalColumnSize = os.popen('stty size', 'r').read().split()
20+
21+
parser = argparse.ArgumentParser(description=
22+
"""ls command alternative.
23+
Output is either cleanly formatted table or
24+
string of null terminated file names parseable by xargs command.
25+
Default behaviour is to show only non-hidden files (no directories) of
26+
directory passed or current directory if no directory is given in table format.
27+
""")
28+
29+
parser.add_argument('-x','--xargs', action="store_true",
30+
help="output will be string of null terminated file names.\
31+
Can be used as input to other commands like xargs. \
32+
Absense of this option makes output to be a table, which is default")
33+
34+
group1 = parser.add_mutually_exclusive_group()
35+
group1.add_argument("-n", "--non-hidden", action='store_true', dest="non_hidden",
36+
help="show files (and directories with -w) with names that does \
37+
not start with a dot. This is default")
38+
group1.add_argument("-i", "--hidden", action='store_true',
39+
help="show files (and directories with -w) with names starting with a dot")
40+
group1.add_argument("-a", "--include-hidden", action='store_true', dest="include_hidden",
41+
help="show all files (and directories with -w), including hidden ones")
42+
43+
group2 = parser.add_mutually_exclusive_group()
44+
group2.add_argument("-d", "--only-dir", action="store_true", dest="only_dir",
45+
help="show directories only and not regular file")
46+
group2.add_argument("-w", "--include-dir", action="store_true", dest="include_dir",
47+
help="show directories along with files. Can be used with option -n, -i or -a")
48+
49+
parser.add_argument("files", metavar="FILE", nargs='*',
50+
help="""space separated list of any numbers of files and/or directories.
51+
If not given current directory will be assumed""")
52+
53+
parser.add_argument("-v", "--version",
54+
help="output version information and exit", action="store_true")
55+
56+
args = parser.parse_args()
57+
58+
# non-hidden is default option
59+
if not args.non_hidden and not args.hidden and not args.include_hidden:
60+
args.non_hidden = True
61+
62+
63+
"""function declarations STARTS here"""
64+
65+
def version():
66+
"""Print version, license and exit"""
67+
if args.version:
68+
print(
69+
"""lsi version 0.1
70+
71+
Copyright (c) 2017 js-d-coder (www.github.com/js-d-coder)
72+
73+
This project is free software released under the MIT/X11 license:
74+
75+
Permission is hereby granted, free of charge, to any person obtaining a copy
76+
of this software and associated documentation files (the "Software"), to deal
77+
in the Software without restriction, including without limitation the rights
78+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
79+
copies of the Software, and to permit persons to whom the Software is
80+
furnished to do so, subject to the following conditions:
81+
82+
The above copyright notice and this permission notice shall be included in
83+
all copies or substantial portions of the Software.
84+
85+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
86+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
87+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
88+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
89+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
90+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
91+
THE SOFTWARE.
92+
""")
93+
sys.exit(0)
94+
95+
96+
def createFileList(dirname):
97+
"""create list of files in given directory based on various options"""
98+
dirContents = []
99+
all = os.listdir(dirname)
100+
if args.non_hidden:
101+
if args.include_dir:
102+
dirContents = [file for file in all if not os.path.isdir(dirname + "/" + file) and file[0] != '.' ]
103+
dirContents += [file+"/" for file in all if os.path.isdir(dirname + "/" + file) and file[0] != '.' ]
104+
elif args.only_dir:
105+
dirContents = [file+"/" for file in all if os.path.isdir(dirname + "/" + file) and file[0] != '.' ]
106+
else:
107+
dirContents = [file for file in all if not os.path.isdir(dirname + "/" + file) and file[0] != '.' ]
108+
elif args.hidden:
109+
if args.include_dir:
110+
dirContents = [file for file in all if not os.path.isdir(dirname + "/" + file) and file[0] == '.' ]
111+
dirContents += [file+"/" for file in all if os.path.isdir(dirname + "/" + file) and file[0] == '.' ]
112+
elif args.only_dir:
113+
dirContents = [file+"/" for file in all if os.path.isdir(dirname + "/" + file) and file[0] == '.' ]
114+
else:
115+
dirContents = [file for file in all if not os.path.isdir(dirname + "/" + file) and file[0] == '.' ]
116+
else:
117+
if args.include_dir:
118+
dirContents = [file for file in all if not os.path.isdir(dirname + "/" + file)]
119+
dirContents += [file+"/" for file in all if os.path.isdir(dirname + "/" + file)]
120+
elif args.only_dir:
121+
dirContents = [file+"/" for file in all if os.path.isdir(dirname + "/" + file)]
122+
else:
123+
dirContents = [file for file in all if not os.path.isdir(dirname + "/" + file)]
124+
return dirContents
125+
126+
127+
def xargsInput():
128+
"""create string of null terminated file names for processing by xargs command"""
129+
outputString = ""
130+
for file in args.files:
131+
if not os.path.isdir(file):
132+
outputString += file + "0円"
133+
else:
134+
for inode in createFileList(file):
135+
outputString += file + "/" + inode + "0円"
136+
return outputString
137+
138+
139+
def prettyPrint(list):
140+
"""print files in table format"""
141+
maxlen = 0
142+
for l in list:
143+
if len(l) > maxlen:
144+
maxlen = len(l)
145+
colWidth = maxlen + 4
146+
noOfCol = int(int(terminalColumnSize)/colWidth)
147+
n = 1
148+
if noOfCol == 0:
149+
for f in list:
150+
print("{!r}".format(f))
151+
else:
152+
for f in list:
153+
print('{!r}'.format(f).ljust(colWidth), end="")
154+
if n == noOfCol:
155+
n = 0
156+
print("")
157+
n += 1
158+
print("\n")
159+
160+
"""function declarations ENDS here"""
161+
162+
163+
def main():
164+
global didErrorOccur
165+
version()
166+
if not len(args.files):
167+
"""if no argument is given, assume it to be current directory"""
168+
args.files = ['.']
169+
if args.xargs:
170+
"""if -x or --xargs is given, output string of null terminated file names"""
171+
try:
172+
print(xargsInput(), end="")
173+
sys.exit(0)
174+
except FileNotFoundError as err:
175+
print(err)
176+
sys.exit(2)
177+
except PermissionError as err:
178+
print(err)
179+
sys.exit(2)
180+
else:
181+
"""if -x or --xargs is not given, output file names in table format"""
182+
183+
for file in args.files:
184+
"""keep processing next file in the files list even if error occur.
185+
if error occur print the error and process next file in the files list.
186+
didErrorOccur is used as a flag whether error occur or not"""
187+
try:
188+
if not os.path.exists(file):
189+
raise FileNotFoundError("{}: cannot access '{}': no such file or directory\n".format(os.path.basename(sys.argv[0]), file))
190+
elif not os.path.isdir(file):
191+
print(file, end="\n\n")
192+
else:
193+
if len(args.files) > 1:
194+
print(file, ":", sep="")
195+
prettyPrint(createFileList(file))
196+
except FileNotFoundError as err:
197+
print(err)
198+
didErrorOccur = 1
199+
except PermissionError:
200+
print("{}: cannot open directory '{}': Permission denied\n".format(os.path.basename(sys.argv[0]), file))
201+
didErrorOccur = 1
202+
203+
204+
if __name__ == "__main__":
205+
didErrorOccur = 0 # used as a flag whether error occur or not
206+
main()
207+
if didErrorOccur:
208+
sys.exit(2)
209+
else:
210+
sys.exit(0)

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /