powershell/python_shell编写可以指定递归深度的powershell tree命令/ls递归遍历符号链接symlink/仅遍历文件夹/遍历文件和目录/指定遍历深度/如何绘制树干

ls(get-childItem)递归遍历符号链接symlink

-FollowSymlink <System.Management.Automation.SwitchParameter>
By default, the `Get-ChildItem` cmdlet displays symbolic links to directories found during recursion, but doesn't recurse into them. Use the FollowSymlink parameter to search the
directories that target those symbolic links. The FollowSymlink is a dynamic parameter and is supported only in the FileSystem provider.
## powershell version
  • 默认情况下,ls -R不会遍历到符号链接/junction link所指的目录
  • 明白这一点在某些情况下很重要(特别是下文中的模拟tree的函数)
    • 该版本也是默认不会遍历进入符号链接,不过,您可以指定-FollowSymlink来迫使遍历能够访问符号链接所指向的目录

powershell version(no tree branch)

  • 可以自行修改或者结合管道符进行更高级的处理
function tree_pwsh
{
# Closure function
<#
.synopsis
本函数支持遍历目录和文件
也可以选择仅遍历目录而部列出文件
通过缩进来表示嵌套层次关系
支持指定最大遍历深度;指定为0时,表示不限制深度
.example
recurseClosure -traverseType d -maxDepth 3
recurseClosure -traverseType a -maxDepth 3 -path D:\repos\scripts\linuxShellScripts\
排除关键字示例(可以修改-eq为-like / -match 来支持通配符或正则表达式)
recurseTree -exclude "node_modules" -maxDepth 0 |sls -Pattern "Rand.*"
#>
# 参数置顶原则
param(
$traverseType = '',
$path = './',
$maxDepth = '2',
$exclude = ''
)
$depth = 1
$times = 0
function listRecurse
{
<# 遍历所有子目录 #>
param(
$traverseType = '',
$path = ''
)
# Write-Output "`tpath=$path"
if ($traverseType -eq 'd')
{
$lst = (Get-ChildItem -Directory $path)
}
else
{
$lst = (Get-ChildItem $path)
}
# 子目录数目len
$len = $lst.Length
$times++;
#每一层处理都是都是一重循环O(n)
# 遍历子目录
<# 注意需要添加对文件的判断,否则在对文件调用本函数的时候,会陷入死循环(无法进入深层目录) #>
$lst | ForEach-Object {
$len--;
# Write-Output "`t`t remain times :len=$len";
if ($_.BaseName -like $exclude)
{
# pass it
}
else
{
# 打印每个子目录及其深度
# 无树干的前缀字符串(简洁版)
# $indent = "`t" * ($depth - 1)
# 如果想要画出所有的枝干,需要在intend这段字符串做改进(不单单是合适数量的制表符.)
# 总之,每一行可能有多个`|`:第n层的条目,需要有n条树干线(而且,同一行的内容只能够一次性打印完,)
# 所以,我们应该计算并安排好每一行的前缀字符串(树干线)
# 带树干的字符串:│ ├ ─ └ ─ |
$indent_tree = "│`t" * ($depth - 1) + '│'
# 打印路径
$pathNameRelative= $_.baseName
Write-Output "$indent_tree`──($depth)$($pathNameRelative)"
if ((Get-Item $_) -is [system.io.directoryinfo] )
{
# 打印树干
# 其实还要考虑要求打印的深度的截至
if (@(Get-ChildItem $_).Count -gt 0 )
{
# Write-Output @(Get-ChildItem $_).Count
# $branch = '|' + "`t" * ($depth - 1) + ' \____.'
$branch = $indent_tree + ' ├────'
# $branch = $indent_tree
if ($depth -eq $maxDepth)
{
<# Action to perform if the condition is true #>
$branch += '......'
}
$branch
}
$depth++
# write
# 对子目录继续深挖,(做相同的调用)
if ($depth -le $maxDepth -or $maxDepth -eq 0)
{
listRecurse -path $_.FullName -traverseType $traverseType
}
$depth--
}
# Write-Output "$depth"
# Start-Sleep -Milliseconds 1000
}
}
}
listRecurse -traverseType $traverseType -path $path
# listRecurse
}

示例效果

PS D:\repos\blogs\neep> recurseTree -maxDepth 3
1 D:\repos\blogs\neep\408
2 D:\repos\blogs\neep\408\ComputerNetwork
3 D:\repos\blogs\neep\408\ComputerNetwork\concepts.md
3 D:\repos\blogs\neep\408\ComputerNetwork\ipv6.md
2 D:\repos\blogs\neep\408\os
3 D:\repos\blogs\neep\408\os\exercise5.md
2 D:\repos\blogs\neep\408\principlesOfCompilers
3 D:\repos\blogs\neep\408\principlesOfCompilers\image
3 D:\repos\blogs\neep\408\principlesOfCompilers\subSet.md
2 D:\repos\blogs\neep\408\principlesOfComputer
3 D:\repos\blogs\neep\408\principlesOfComputer\机器数问题
3 D:\repos\blogs\neep\408\principlesOfComputer\image
3 D:\repos\blogs\neep\408\principlesOfComputer\1646647596000.png
3 D:\repos\blogs\neep\408\principlesOfComputer\补码和模的故事.md
3 D:\repos\blogs\neep\408\principlesOfComputer\存储单元地址.md

powershell tree_pwsh(with tree branch)

function tree_pwsh
{
# Closure function
<#
.synopsis
本函数支持遍历目录和文件
也可以选择仅遍历目录而部列出文件
通过缩进来表示嵌套层次关系
支持指定最大遍历深度;指定为0时,表示不限制深度
.example
recurseClosure -traverseType d -maxDepth 3
recurseClosure -traverseType a -maxDepth 3 -path D:\repos\scripts\linuxShellScripts\
排除关键字示例(可以修改-eq为-like / -match 来支持通配符或正则表达式)
recurseTree -exclude "node_modules" -maxDepth 0 |sls -Pattern "Rand.*"
#>
# 参数置顶原则
param(
$traverseType = '',
$path = './',
$maxDepth = '2',
$exclude = ''
)
$depth = 1
$times = 0
function listRecurse
{
<# 遍历所有子目录 #>
param(
$traverseType = '',
$path = ''
)
# Write-Output "`tpath=$path"
if ($traverseType -eq 'd')
{
$lst = (Get-ChildItem -Directory $path)
}
else
{
$lst = (Get-ChildItem $path)
}
# 子目录数目len
$len = $lst.Length
$times++;
#每一层处理都是都是一重循环O(n)
# 遍历子目录
<# 注意需要添加对文件的判断,否则在对文件调用本函数的时候,会陷入死循环(无法进入深层目录) #>
$lst | ForEach-Object {
$len--;
# Write-Output "`t`t remain times :len=$len";
if ($_.BaseName -like $exclude)
{
# pass it
}
else
{
# 打印每个子目录及其深度
# 无树干的前缀字符串(简洁版)
# $indent = "`t" * ($depth - 1)
# 如果想要画出所有的枝干,需要在intend这段字符串做改进(不单单是合适数量的制表符.)
# 总之,每一行可能有多个`|`:第n层的条目,需要有n条树干线(而且,同一行的内容只能够一次性打印完,)
# 所以,我们应该计算并安排好每一行的前缀字符串(树干线)
# 带树干的字符串
$indent_tree = "|`t" * ($depth - 1)
Write-Output "$indent_tree`\_($depth)$($_.FullName)"
if ((Get-Item $_) -is [system.io.directoryinfo] )
{
# 打印树干
# 其实还要考虑要求打印的深度的截至
if (@(Get-ChildItem $_).Count -gt 0 )
{
# Write-Output @(Get-ChildItem $_).Count
# $branch = '|' + "`t" * ($depth - 1) + ' \____.'
$branch = $indent_tree+ ' \____.'
if ($depth -eq $maxDepth)
{
<# Action to perform if the condition is true #>
$branch += '......'
}
$branch
}
$depth++
# write
# 对子目录继续深挖,(做相同的调用)
if ($depth -le $maxDepth -or $maxDepth -eq 0)
{
listRecurse -path $_.FullName -traverseType $traverseType
}
$depth--
}
# Write-Output "$depth"
# Start-Sleep -Milliseconds 1000
}
}
}
listRecurse -traverseType $traverseType -path $path
# listRecurse
}

效果

在这里插入图片描述

updating version

  • 将每层的文件和目录分类(优先答应文件,然后在处理文件夹,使得结果更加紧凑)
"""
设定一个递归函数travers_dir(dirName,depthStop,...);
该函数支持指定递归的深度;
同时要求能够体现目录间的层次(通过制表符缩进来表达 🅱 )
具体规则如下:当指定深度depth_stop<=0时,尽可能的递归当前目录下的子目录(否则递归的深度就是depth_stop,或者不超过depth_stop);
默认尽可能递归.
该函数接收一个目录字符串参数,函数进入改目录打印出所有文件名以及目录名此外,如果被打印的对象时目录时,需要以该目录为参数在调用一次traverse_dir
在以下实现中,您不应当传入第三个参数,如果为了安全起见,您可以为其在做一次浅封装,使得函数只有两个参数,而函数内部则调用traverse_dir()
"""
from sys import argv
import os
import os.path as op
# 定义一个空函数,来控制日志打印与否(免注释)
def empyt(obj):
...
d = print
# 控制是否打印调试日志
d = empyt
pathOut = "fileOutByTreePyScript"
""" 本函数主要用到:os.listdir()以及os.path.isdir()以及一些判断技巧和debug过程中的控制技巧,去掉日志语句后,代码量较少 """
def separate_line(num=50 ,separator='>'):
print(f'😎🎶:{num*separator}')
def traverse_dir(dirName=".", stop_depth=0, depth=0):
if depth == 0:
separate_line(separator='~')
print(
f'😁executing the traverse_dir with the paramters: \n@dirName={dirName},\n@stop_depth={stop_depth},\n@depth={depth}')
separate_line(separator='^')
if stop_depth > 0:
if stop_depth > depth:
pass
else:
return
d("\t new invoke of traverse_dir()")
items = os.listdir(dirName)
# print(items)
# for item in items:
# newPath = op.join(dirName, item)
# print(newPath)
# print(op.isfile(newPath))
items.sort(key=lambda item: op.isdir(op.join(dirName, item)))
# separate_line()
# print(items)
d(items)
if (items):
for item in items:
# newPath = dirName+"/"+item
# newPath的存在性可以保证,但是是否为目录需做进一步判断
newPath = op.join(dirName, item)
d(newPath)
# notice the paramter of isdir()
isdir = op.isdir(newPath)
if isdir:
# print(isdir)
if item == ".git":
continue
d("dirName:"+item+"\twill be enter by new invoke of traverse_dir")
# leftEmoji = "-------😇-------"
# rightEmoji = "-------🙂-------"
fileLogo = "☪ "
folder_Logo = "📁"
dir_logo="->"
depthStr = folder_Logo+"depth:"+str(depth+1)+dir_logo
indent = depth*"\t"
dirStr = newPath
#
dirStr = indent+depthStr+ dirStr
print(dirStr)
# out(dirStr)f
traverse_dir(newPath, stop_depth, depth+1)
else:
fileStr = depth*"\t"+0*" "+"⭐:"+item
print(fileStr)
# out(fileStr)
def append(content, fileName=pathOut):
with open(fileName, 'a') as fout:
# 注意换行
fout.write(content+"\n")
def generate_defaultParams():
# dirName = "d:/repos/learnPython/ppt_source_code"
# dirName = "./../algorithm/"
dirPrefix = "d:/repos/scripts/"
# dirPost = "algorithm"
dirPost = ""
# dirName = op.join(dirPrefix, dirPost)
return dirPrefix+dirPost
# 当反复调试的时候可以预处理将之前的文件删除
# 如果有必要,可以采用将原来的文件重名名的方式(以输出时间为名字后缀是一种选择)
if op.exists(pathOut):
# 或者用rename()
os.remove(pathOut)
if __name__ == "__main__":
# test
os.chdir(os.getcwd())
# print(os.getcwd(), "😁😁😁")
# traverse_dir(".",2)
separate_line(separator="-")
print("😊info:there is in the tree_pyScript.py;\n try to offer the tree server...💕")
# if the CLI didn't offer the parameter for the script,then run the statement:
dirName = "." # default direcotry(current work directory)
dirName = generate_defaultParams()
depth = 2
# modify the dirName according the parameter(parameter judging&correcting...)
# case0:more than 1 parameter.
if len(argv) > 1:
# scriptName=argv[0]
# case1: more than 2 parameters
dirName = argv[1]
if len(argv) > 2:
# print(f"get the argv from commandLine:{argv[1]}😊{argv[2]}")
depth = argv[2] # the 2nd parameter will be regarded as stopDepth(as default);
if(argv[2].isdigit()):
depth = int(depth)
# judge if user input the name parameter(keyword parameter.)
#todo complete this implement
if(argv[1].startswith("depth=")):
depth = int(argv[1][6:])
print(argv[1][6:])
else:
...#keep the argv[1] as raw input.(as dirName)
if(argv[2].startswith("dirName=")):
dirName = argv[2][len("dirName="):]
if(argv[1] in ["-?", "?", "/?", "\\?"]):
print("function usage:traverse_dir([dirName],[depth]💕")
else:
print("you do not offer any parameter,now try execute the default behaviour💕")
traverse_dir(dirName, depth)
tip='😘work dir tips for user:'
separate_line()
print(tip,"\n",os.getcwd(),f'😘')

preview

在这里插入图片描述

old version

"""
"""
设定一个递归函数travers_dir(dirName,depthStop,...);
该函数支持指定递归的深度;
同时要求能够体现目录间的层次(通过制表符缩进来表达 🅱 )
具体规则如下:当指定深度depth_stop<=0时,尽可能的递归当前目录下的子目录(否则递归的深度就是depth_stop,或者不超过depth_stop);
默认尽可能递归.
该函数接收一个目录字符串参数,函数进入改目录打印出所有文件名以及目录名此外,如果被打印的对象时目录时,需要以该目录为参数在调用一次traverse_dir
在以下实现中,您不应当传入第三个参数,如果为了安全起见,您可以为其在做一次浅封装,使得函数只有两个参数,而函数内部则调用traverse_dir()
"""
from sys import argv
import os
import os.path as op
# 定义一个空函数,来控制日志打印与否(免注释)
def empyt(obj):
...
d = print
# 控制是否打印调试日志
d = empyt
""" 本函数主要用到:os.listdir()以及os.path.isdir()以及一些判断技巧和debug过程中的控制技巧,去掉日志语句后,代码量较少 """
def traverse_dir(dirName=".", stop_depth=0, depth=0):
# depth=0
if stop_depth > 0:
if stop_depth > depth:
pass
else:
return
d("\t new invoke of traverse_dir()")
items = os.listdir(dirName)
d(items)
if (items):
for item in items:
# newPath = dirName+"/"+item
# newPath的存在性可以保证,但是是否为目录需做进一步判断
newPath = op.join(dirName, item)
d(newPath)
# notice the paramter of isdir()
if op.isdir(newPath):
if item == ".git":
continue
d("dirName:"+item+"\twill be enter by new invoke of traverse_dir")
leftEmoji = "-------😇-------"
rightEmoji = "-------🙂-------"
depthStr = "detpth:"+str(depth+1)
indent = depth*"\t"
dirStr = newPath
fileLogo = "☪ "
folderLogo = "📁 "
dirStr = indent+depthStr+folderLogo + dirStr
print(dirStr)
# out(dirStr)
traverse_dir(newPath, stop_depth, depth+1)
else:
fileStr = depth*"\t"+"⭐:"+item
print(fileStr)
# out(fileStr)
""" """
pathOut = "file_dir_out"
def append(content, fileName=pathOut):
with open(fileName, 'a') as fout:
# 注意换行
fout.write(content+"\n")
# dirName = "d:/repos/learnPython/ppt_source_code"
# dirName = "./../algorithm/"
dirPrefix = "d:/repos/PythonLearn/"
dirPost = "algorithm"
dirPost = ""
# dirName = op.join(dirPrefix, dirPost)
dirName = dirPrefix+dirPost
# 当反复调试的时候可以预处理将之前的文件删除
# 如果有必要,可以采用将原来的文件重名名的方式(以输出时间为名字后缀是一种选择)
if op.exists(pathOut):
# 或者用rename()
os.remove(pathOut)
# 将中途的输出结果(比如日志)输出到文件中(采用append模式)
out = append
depth = 0
if __name__ == "__main__":
# test
# os.chdir("D:/repos/")
# traverse_dir(".",2)
if len(argv) > 1:
dirName = argv[1]
if len(argv) > 2:
# print(f"get the argv from commandLine:{argv[1]}😊{argv[2]}")
depth = argv[2]
if(argv[2].isdigit()):
depth = int(depth)
if(argv[1].startswith("depth=")):
depth = int(argv[1][6:])
print(argv[1][6:])
if(argv[2].startswith("dirName=")):
dirName = argv[2][len("dirName="):]
if(argv[1] in ["-?", "?", "/?", "\\?"]):
print("traverse_dir(dirName,depth)")
# else:
traverse_dir(dirName, depth)

效果

20211126211421

使用方式

python <脚本名> 目录名 深度(0则为无限深度)
例如:
python tr_py d:\repos\web 2

posted @   xuchaoxin1375  阅读(8)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示