我有一个父文件夹、子文件夹以及文件夹和子文件夹内的文件的列表。我使用以下命令行列出父文件夹和子文件夹的内容:
tree > index.txt
“index.txt”中的输出如下
.
|_ sdc
| |_ QA
| | |_ sp
| | | |_ data
| | | | | |_10507
| | | | | | |_01.txt
| | | | | | |_02.txt
| | | | | | |_03.zip
如果其中一个文件是 zip 文件,如何打印文件名旁边每个文件的第一行和第二行是否可以打印其内容以及第一行和第二行,如下所示:
.
|_ sdc
| |_ QA
| | |_ sp
| | | |_ data
| | | | | |_10507
| | | | | | |_01.txt <first line> <secondline>
| | | | | | |_02.txt <first line> <secondline>
| | | | | | |_03.zip
| | | | | | | |_01.txt <first line> <secondline>
| | | | | | | |_02.txt <first line> <secondline>
| | | | | | | |_03.txt <first line> <secondline>
我曾经用来sed -n '2p;d'
从任何文件中打印我想要的行,但是如何将它与“树”命令行并排使用,或者是否有任何建议那就太好了?
答案1
本答案末尾的 python 脚本不能完全满足您的要求,但应该很接近。我添加了目录10999
以显示如何显示同一级别的目录。
此代码不能很好地处理 zip 文件中的子目录,为此您最好编写一个可以递归调用自身的 zip_recurse 例程。
该代码已在 Python 2.6.9、2.7.9、3.3.6 和 3.4.2 上进行了测试
$ mkdir -p sdc/QA/SP/data/10507
$ echo -e '01 line 1\n01 line 2\n01 line 3' > sdc/QA/SP/data/10507/01.txt
$ echo -e '02 line 1\n02 line 2\n02 line 3' > sdc/QA/SP/data/10507/02.txt
$ echo -e '03 line 1\n03 line 2\n03 line 3' > sdc/QA/SP/data/10507/03.txt
$ mkdir -p sdc/QA/SP/data/10999
$ echo -e '04 line 1\n04 line 2\n04 line 3' > sdc/QA/SP/data/10999/04.txt
$ pushd sdc/QA/SP/data/10507/
$ zip 03.zip *.txt
$ rm 03.txt
$ popd
$ python test.py sdc
└── QA/
└── SP/
└── data/
├── 10507/
│ ├── 01.txt: 01 line 1\n: 01 line 2\n
│ ├── 02.txt: 02 line 1\n: 02 line 2\n
│ └── 03.zip
│ └── 01.txt: 01 line 1\n01 line 2\n
│ └── 02.txt: 02 line 1\n02 line 2\n
│ └── 03.txt: 03 line 1\n03 line 2\n
└── 10999/
└── 04.txt: 04 line 1\n: 04 line 2\n
test.py
:
#! /usr/bin/env python
# coding: utf-8
from __future__ import with_statement
import sys
import os
from zipfile import ZipFile
class ListTree:
# tree characters
indent = 2
def __init__(self, characters=None):
""" characters should be None for graphical, "ASCII" for non
graphical (+|`-) or a four letter sequence
"""
if characters is None:
self._char = u'├│└─'
elif characters == 'ASCII':
self._char = '+|`-'
else:
self._char == characters
assert len(self._char) == 4
def out(self, endmarkers, val, fp=None):
# endmarkers is a list with the length of the list indicating
# the depth and True values if at that depth this entry is the last one
stream = fp if fp else sys.stdout
s = u''
for idx, n in enumerate(endmarkers):
if idx == len(endmarkers) - 1:
if n:
s += self._char[2] + self._char[3] * self.indent
else:
s += self._char[0] + self._char[3] * self.indent
else: # not last one
if n:
s += ' ' * (self.indent + 2)
else:
s += self._char[1] + ' ' * (self.indent + 1)
msg = u'{0} {1}\n'.format(s, val)
if sys.version_info < (3,):
msg = msg.encode('utf-8')
stream.write(msg)
class WalkTree(object):
def __init__(self, base_dir):
lt = ListTree()
old_dir = os.getcwd()
os.chdir(base_dir)
for n, x in self.recurse('.'):
lt.out(n, x)
os.chdir(old_dir)
def recurse(self, path, prev=[]):
# could use os.walk() but would have to combine the dir and file_name
# lists, sort them and split apart, or keep the lists sorted separate
# and check from which one to take the next entry
lst = sorted(
[x for x in os.listdir(path) if x and not x[0] == '.'])
lidx = len(lst) - 1
for idx, x in enumerate(lst):
n = prev[:] + [idx == lidx]
dpath = os.path.join(path, x)
if os.path.isdir(dpath):
x += '/'
yield n, x
for y in self.recurse(dpath, n):
yield y
else:
if os.path.splitext(x)[1] == '.txt':
with open(dpath) as fp:
for count in range(2):
x += ': ' + fp.readline().replace('\n', '\\n')
elif os.path.splitext(x)[1] == '.zip':
yield (n, x)
n1 = n[:] + [idx == lidx]
# ZipFile in 2.6 doesn't have __enter__/__exit__ yet
zf = ZipFile(dpath)
for info in zf.infolist():
x1 = info.filename
if os.path.splitext(x1)[1] == '.txt':
data = zf.read(x1)
if sys.version_info >= (3,):
data = str(data, encoding='utf-8')
x1 += ': ' + '\\n'.join(data.split(
'\n', 2)[:2]) + '\\n'
yield(n1, x1)
zf.close()
return
yield (n, x)
wt = WalkTree('.' if len(sys.argv) < 2 else sys.argv[1])