【问题标题】:Powershell Get -ChildItem: filtering csv files and -Recurse not workingPowershell Get -ChildItem:过滤 csv 文件和 -Recurse 不起作用
【发布时间】:2019-05-30 19:06:23
【问题描述】:

我创建了一个简短的 powershell 脚本来将 csv 文件从 Unicode 转换为 UTF-8 编码。我的脚本以原始文件名以 UTF8 开头的新文件输出。我遇到了两个问题:

  1. 我正在尝试仅在 csv 文件上运行 powershell 脚本。目前该脚本在目录中的每个文件上运行,包括 powershell 脚本(例如,如果 powershell 脚本被称为 pshell_script,它会输出一个名为 UTF8pshell_script 的新文件)。我尝试仅在 csv 文件上运行脚本的其他方法最终使脚本不执行任何操作。

  2. 我正在尝试在子目录上运行脚本。第一个问题是从子目录中的 csv 文件创建的输出文件中没有任何内容。如果脚本与 csv 文件在同一目录中运行,则不会出现此问题。这并不重要,但我也不确定如何从子目录中创建的输出文件输出到相同的子目录中(当前它们输出到 powershell 脚本所在的主目录中)。 作为

    Get-Content -Encoding Unicode $_ | Out-File -Encoding UTF8
    Get-ChildItem -Recurse | ForEach-Object {Get-Content -Encoding Unicode $_ | Out-File -Encoding UTF8 "UTF8$_"}

所需的输出是仅在 csv 文件上运行的 powershell 脚本,并将文件输出到创建它们的文件所在的相同子目录。

【问题讨论】:

    标签: powershell


    【解决方案1】:

    根据原始编码(以及 BOM 的存在),您可能还必须在输入端指定编码。

    ForEach($Csv in (Get-ChildItem -Filter *.csv -Recurse -Exclude UTF8*)){
      (Get-Content $Csv.FullName -raw) | 
        Set-Content -Path {Join-Path $Csv.Directory ("UTF8"+$Csv.Name)} -Encoding UTF8
    }
    

    【讨论】:

    • 这会正确地将 csv 文件输出到其正确的子目录,但不会显示原始 csv 文件中的大部分内容(它只显示原始 csv 文件中一行的值)
    • 因为脚本除了用不同的-Encoding 保存之外没有改变内容我有点好奇,-Encoding 对原始文件做了什么有 i>?
    • 我将它附加到脚本中。
    • 同样的事情还在发生。如果您想在本地测试脚本,这里有两个我正在使用的示例 csv 文件: csv1:anonymousfiles.io/MfUViaJp csv2:anonymousfiles.io/tPezSszV powershell script:anonymousfiles.io/wbR6CPzA
    • 将脚本更改为使用 -raw 参数和 Get-Content,现在输出完全相同。
    【解决方案2】:

    LotPings 以几乎相同的答案击败了我 10 分钟,但我将其保留为我所拥有的“将空文件传递到管道”位。我也意识到,出于同样的原因,您不需要管道变量,因为只有在循环内通过管道传递事物时才需要它。

    如果您只想更改编码,我将使用ForEach($x in $y){} 循环,或者在Get-ChildItem 上使用带有PipelineVariableForEach-Object{} 循环。我将展示这一点,因为我认为管道变量未得到充分利用。我也不会读取文件并将其通过管道传递给某些东西,因为如果文件为空,您将不会创建新文件,因为没有任何东西通过管道传递。

    Get-ChildItem *.csv -Recurse -PipelineVariable File | ForEach-Object{
        Set-Content -Value (Get-Content $File.FullName -Encoding Unicode) -Path {Join-Path $File.Directory "UTF8$($File.Name)"} -Encoding UTF8
    }
    

    【讨论】:

    • 这似乎没有输出任何东西
    【解决方案3】:

    Get-ChildItem 采用-Filter 参数,对于文件来说是简单的通配符模式。这将允许您将 cmdlet 限制为仅 CSV 文件:

    Get-ChildItem -Filter *.csv
    

    要处理子目录,您也可以使用-Recurse 开关

    Get-ChildItem -Filter *.csv -Recurse
    

    现在,我不太确定 $_ 在您通过管道传递不同对象时如何变化,因此我可能不会以最有效的方式执行后续步骤 - 但很清楚我正在尝试什么要做的事:

    我们找到的每个文件对象都需要进行如下处理:

    1. 分解成路径和文件名:$filepath = $_.PSParentPath; $filename = $_.PSChildName
    2. 加载 CSV:Import-CSV -Path $_
    3. 使用正确的编码输出新的 CSV:Export-CSV -Path ("{0}\UTF8{1}" -f $filepath,$filename) -Encoding UTF8

    所以,我们把它们放在一起:

    Get-ChildItem -Filter *.csv -Recurse -exclude UTF8* | ForEach-Object { 
        $filepath = $_.PSParentPath
        $filename = $_.PSChildName
        Import-CSV -Path $_ | 
           Export-CSV -Encoding UTF8 -Path ("{0}\UTF8{1}" -f $filepath,$filename) -NoTypeInformation
    }
    

    Get-ChildItem 中的-Exclude UTF8* 可确保在您创建文件时,它不会在以后被拾取并重新处理。 -NoTypeInformation Export-CSV 上的 -NoTypeInformation 弥补了 cmdlet 内置的愚蠢行为,该错误导致在文件开头出现带有无意义对象类型名称的额外行。

    【讨论】:

    • 当使用Import-Csv 时,我也会使用Export-Csv,但如果没有标题(并且第一行数据没有唯一字段),您的方法可能会失败。
    • @LotPings - 很好,我应该在Export-CSV 中包含-NoTypeInformation,即使您认为导入的CSV 是完美的。
    • 老实说,如果他只是在进行编码转换,他并不关心内容,所以Import-Csv将所有内容转换为对象,然后Export-Csv将所有内容转换回文本只是一大堆额外的周期。
    • 这正是我一直在寻找的,唯一的问题(但不重要)是在每个目录中为每个现有的 csv 创建了两个文件,而不是一个。第一个标题为 UTF8 + 文件名,第二个标题为 UTF8UTF8 + 文件名(它们是相同的)
    • @LotPings - -Exclude 的好消息!我怀疑我假设 Get-ChildItem 将在 Export-CSV 运行时完成执行......
    【解决方案4】:

    如果您在Get-ChildItem 的末尾指定文件扩展名。 这将只获取扩展名为 .csv 的文件。

    通过在 Out-File 中指定文件路径,它会将其发送到指定目录。

    Get-ChildItem -Path C:\folder\*.csv -Recurse | ForEach-Object {Get-Content -Encoding Unicode $_ | Out-File -FilePath C:\Folder -Encoding UTF8 "UTF8$_"}
    

    【讨论】:

    • @LotPings 扁平化子目录是什么意思?
    • OP 要求的第 2 点。您正在使用 gci 递归并应用固定文件夹进行输出。
    • 这就是@Jeff Zeitlin 使用 $_.PSParentpath 的原因。他最接近 OPs 问题
    • 这似乎也没有输出任何东西
    猜你喜欢
    • 2020-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-21
    • 2012-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多