【问题标题】:Run Powershell to convert all the csv files to tab delimited text within the same folder运行 Powershell 将所有 csv 文件转换为同一文件夹中的制表符分隔文本
【发布时间】:2020-10-23 08:42:53
【问题描述】:

我是 Powershell 的新手。不知何故,我设法使用以下脚本将 csv 转换为带有制表符分隔的文本。现在我想将可执行脚本保存在保存 csv 的文件夹中。如果脚本被执行,那么它应该转换所有带有.csv 的文件应该在同一个文件夹中转换。

我目前指定路径的工作脚本如下(Powershell 版本 5.1)

$source = "C:\test.csv"
$destination = "C:\newfile.txt"
(Import-CSV $source| 
 ConvertTo-csv -Delimiter "`t" -NoTypeInformation | 
 Select-Object -Skip 1) -replace '"' | Set-Content $destination

【问题讨论】:

  • 只需使用.\file.csv 作为您的来源和位置,并将脚本另存为 .ps1 文件
  • 您要转换为制表符分隔的所有这些 csv 文件中使用的分隔符是什么?显然,您还想去掉标题行并删除所有引号。我会将输出文件扩展名更改为.tab,以免覆盖原始文件。此外,简单地删除所有引号字符是危险的,因为有时字段包含分隔符并且这些字段必须被引用。否则,字段对齐将中断,您将不再拥有有效文件..
  • 我使用的文件没有引号。如您所说,最好将其保存为标签文件。我不想修改旧文件,只需要修改“新文件”。

标签: powershell


【解决方案1】:

遍历脚本所在文件夹中的文件,您可以使用$PSScriptRoot 自动变量。

正如评论的那样,简单地删除所有引号是不安全的,因为 csv 文件可能有字段包含 TAB 分隔符,如果您不引用这些值,则生成的文件将未对齐数据行。

您可以使用我的函数ConvertTo-CsvNoQuotes 安全地删除引号。

function ConvertTo-CsvNoQuotes {
    # returns a csv delimited string array with values unquoted unless needed
    [OutputType('System.Object[]')]
    [CmdletBinding(DefaultParameterSetName = 'ByDelimiter')]
    param (
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, Position = 0)]
        [PSObject]$InputObject,

        [Parameter(Position = 1, ParameterSetName = 'ByDelimiter')]
        [char]$Delimiter = ',',

        [Parameter(ParameterSetName = 'ByCulture')]
        [switch]$UseCulture,
        [switch]$NoHeaders,
        [switch]$IncludeTypeInformation  # by default, this function does NOT include type information
    )
    begin {
        if ($UseCulture) { $Delimiter = (Get-Culture).TextInfo.ListSeparator }
        # regex to test if a string contains a double quote, the delimiter character,
        # newlines or has whitespace at the beginning or the end of the string.
        # if that is the case, the value needs to be quoted.
        $needQuotes = '^\s|["{0}\r\n]|\s$' -f [regex]::Escape($Delimiter)
        # a boolean to check if we have output the headers or not from the object(s)
        # and another to check if we have output type information or not
        $doneHeaders = $doneTypeInfo = $false
    }

    process {
        foreach($item in $InputObject) {
            if (!$doneTypeInfo -and $IncludeTypeInformation) {
                '#TYPE {0}' -f $item.GetType().FullName
                $doneTypeInfo = $true
            }
            if (!$doneHeaders -and !$NoHeaders) {
                $row = $item.PsObject.Properties | ForEach-Object {
                    # if needed, wrap the value in quotes and double any quotes inside
                    if ($_.Name -match $needQuotes) { '"{0}"' -f ($_.Name -replace '"', '""') } else { $_.Name }
                }
                $row -join $Delimiter
                $doneHeaders = $true
            }
            $item | ForEach-Object {
                $row = $_.PsObject.Properties | ForEach-Object {
                    # if needed, wrap the value in quotes and double any quotes inside
                    if ($_.Value -match $needQuotes) { '"{0}"' -f ($_.Value -replace '"', '""') } else { $_.Value }
                }
                $row -join $Delimiter
            }
        }
    }
}

在你的脚本之上,这样使用它:

# get all CSV files in the path this script is currently in
Get-ChildItem -Path $PSScriptRoot -Filter '*.csv' -File | ForEach-Object {
    $tabCsv = (Import-Csv -Path $_.FullName) | ConvertTo-CsvNoQuotes -Delimiter "`t" -NoHeaders
    $tabOut = [System.IO.Path]::ChangeExtension($_.FullName, ".tab")
    $tabCsv | Set-Content -Path $tabOut
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-11
    • 1970-01-01
    • 1970-01-01
    • 2017-08-04
    • 1970-01-01
    • 2019-05-31
    • 1970-01-01
    相关资源
    最近更新 更多