Powershell:Import-csv,重命名所有 headers
Powershell: Import-csv, rename all headers
在我们公司,有许多用户和许多应用程序具有受限的访问权限和具有这些访问权限证据的数据库。我无权访问该数据库,但我所拥有的是自动生成的(每天一次)csv 文件,我的所有用户都可以访问。我希望他们有机会检查他们的访问情况,所以我为此编写了一个简单的 powershell 脚本。
CSV:
user;database1_dat;database2_dat;database3_dat
john;0;0;1
peter;1;0;1
我能做到:
import-csv foo.csv | where {$_.user -eq $user}
但这会显示原始丑陋的头饰(带有“_dat”后缀)。当我 无法预测明天会有多少 header 时,我可以删除每个以“_dat”结尾的 header 中的最后四个字符吗?
我知道计算 属性 喜欢:
Select-Object @{ expression={$_.database1_dat}; label='database1' }
但据我所知,我必须知道所有列名。
我是否被定罪通过单独的函数“overingeneer”它并动态地从头开始构建整个“计算的 属性 表达式”,或者我是否缺少一种简单的方法?
谢谢 :-)
你可以这样做:
$textInfo = (Get-Culture).TextInfo
$headers = (Get-Content .\test.csv | Select-Object -First 1).Split(';') |
ForEach-Object {
$textInfo.ToTitleCase($_) -replace '_dat'
}
$user = 'peter'
Get-Content .\test.csv | Select-Object -Skip 1 |
ConvertFrom-Csv -Delimiter ';' -Header $headers |
Where-Object User -EQ $user
User Database1 Database2 Database3
---- --------- --------- ---------
peter 1 0 1
效率不高,但可以解决问题。
假设文件 foo.csv
适合整个内存,以下解决方案执行良好:
- 如果您需要 memory-throttled - 但总是慢得多 - 解决方案,请参阅 Santiago Squarzon's helpful answer 或底部的替代方法。
$headerRow, $dataRows = (Get-Content -Raw foo.csv) -split '\r?\n', 2
# You can pipe the result to `where {$_.user -eq $user}`
ConvertFrom-Csv ($headerRow -replace '_dat(?=;|$)'), $dataRows -Delimiter ';'
Get-Content
-Raw
将整个文件读入内存,比逐行读取(默认)快很多。
-split
'\r?\n', 2
将生成的 multi-line 字符串分成两部分:header 行和所有剩余行。
- 正则表达式
\r?\n
匹配换行符(CRLF (\r\n
) 和 LF-only 换行符 (\n
))
, 2
将标记的数量限制为 return 到 2
,这意味着一旦找到第一个标记(header 行),拆分就会停止,并且输入字符串的其余部分(包括所有数据行)被 returned as-is 作为最后一个标记。
- 注意
$null
作为 multi-assignment 中的第一个目标变量,用于丢弃分隔符正则表达式匹配产生的 empty 标记在字符串的开头。
$headerRow -replace '_dat(?=;|$)'
-replace
'_dat(?=;|$)'
使用正则表达式删除任何 _dat
column-name 后缀(后跟 ;
或字符串结尾);如果子字符串 _dat
仅作为名称 后缀 出现(而不是 inside 名称),您可以简化为 -replace '_dat'
ConvertFrom-Csv
直接接受 arrays 个字符串,所以 cleaned-up header 行和包含所有数据的字符串可以传递行 as-is.
替代解决方案:算法重命名 object 的属性:
注意:此解决方案慢,但如果您仅从中提取 少数 objects,则可能是一个选项CSV 文件。
正如您在问题中所指出的,在您的情况下,使用 Select-Object
with calculated properties 不是一个选项,因为您事先既不知道列名也不知道它们的编号。
但是,您可以使用 ForEach-Object
command in which you use .psobject.Properties
, an intrinsic member,用于 反射 输入 objects:
Import-Csv -Delimiter ';' foo.csv | where { $_.user -eq $user } | ForEach-Object {
# Initialize an aux. ordered hashtable to store the renamed
# property name-value pairs.
$renamedProperties = [ordered] @{}
# Process all properties of the input object and
# add them with cleaned-up names to the hashtable.
foreach ($prop in $_.psobject.Properties) {
$renamedProperties[($prop.Name -replace '_dat(?=.|$)')] = $prop.Value
}
# Convert the aux. hashtable to a custom object and output it.
[pscustomobject] $renamedProperties
}
在我们公司,有许多用户和许多应用程序具有受限的访问权限和具有这些访问权限证据的数据库。我无权访问该数据库,但我所拥有的是自动生成的(每天一次)csv 文件,我的所有用户都可以访问。我希望他们有机会检查他们的访问情况,所以我为此编写了一个简单的 powershell 脚本。
CSV:
user;database1_dat;database2_dat;database3_dat
john;0;0;1
peter;1;0;1
我能做到:
import-csv foo.csv | where {$_.user -eq $user}
但这会显示原始丑陋的头饰(带有“_dat”后缀)。当我 无法预测明天会有多少 header 时,我可以删除每个以“_dat”结尾的 header 中的最后四个字符吗?
我知道计算 属性 喜欢:
Select-Object @{ expression={$_.database1_dat}; label='database1' }
但据我所知,我必须知道所有列名。
我是否被定罪通过单独的函数“overingeneer”它并动态地从头开始构建整个“计算的 属性 表达式”,或者我是否缺少一种简单的方法?
谢谢 :-)
你可以这样做:
$textInfo = (Get-Culture).TextInfo
$headers = (Get-Content .\test.csv | Select-Object -First 1).Split(';') |
ForEach-Object {
$textInfo.ToTitleCase($_) -replace '_dat'
}
$user = 'peter'
Get-Content .\test.csv | Select-Object -Skip 1 |
ConvertFrom-Csv -Delimiter ';' -Header $headers |
Where-Object User -EQ $user
User Database1 Database2 Database3
---- --------- --------- ---------
peter 1 0 1
效率不高,但可以解决问题。
假设文件 foo.csv
适合整个内存,以下解决方案执行良好:
- 如果您需要 memory-throttled - 但总是慢得多 - 解决方案,请参阅 Santiago Squarzon's helpful answer 或底部的替代方法。
$headerRow, $dataRows = (Get-Content -Raw foo.csv) -split '\r?\n', 2
# You can pipe the result to `where {$_.user -eq $user}`
ConvertFrom-Csv ($headerRow -replace '_dat(?=;|$)'), $dataRows -Delimiter ';'
Get-Content
-Raw
将整个文件读入内存,比逐行读取(默认)快很多。-split
'\r?\n', 2
将生成的 multi-line 字符串分成两部分:header 行和所有剩余行。- 正则表达式
\r?\n
匹配换行符(CRLF (\r\n
) 和 LF-only 换行符 (\n
)) , 2
将标记的数量限制为 return 到2
,这意味着一旦找到第一个标记(header 行),拆分就会停止,并且输入字符串的其余部分(包括所有数据行)被 returned as-is 作为最后一个标记。- 注意
$null
作为 multi-assignment 中的第一个目标变量,用于丢弃分隔符正则表达式匹配产生的 empty 标记在字符串的开头。
- 正则表达式
$headerRow -replace '_dat(?=;|$)'
-replace
'_dat(?=;|$)'
使用正则表达式删除任何_dat
column-name 后缀(后跟;
或字符串结尾);如果子字符串_dat
仅作为名称 后缀 出现(而不是 inside 名称),您可以简化为-replace '_dat'
ConvertFrom-Csv
直接接受 arrays 个字符串,所以 cleaned-up header 行和包含所有数据的字符串可以传递行 as-is.
替代解决方案:算法重命名 object 的属性:
注意:此解决方案慢,但如果您仅从中提取 少数 objects,则可能是一个选项CSV 文件。
正如您在问题中所指出的,在您的情况下,使用 Select-Object
with calculated properties 不是一个选项,因为您事先既不知道列名也不知道它们的编号。
但是,您可以使用 ForEach-Object
command in which you use .psobject.Properties
, an intrinsic member,用于 反射 输入 objects:
Import-Csv -Delimiter ';' foo.csv | where { $_.user -eq $user } | ForEach-Object {
# Initialize an aux. ordered hashtable to store the renamed
# property name-value pairs.
$renamedProperties = [ordered] @{}
# Process all properties of the input object and
# add them with cleaned-up names to the hashtable.
foreach ($prop in $_.psobject.Properties) {
$renamedProperties[($prop.Name -replace '_dat(?=.|$)')] = $prop.Value
}
# Convert the aux. hashtable to a custom object and output it.
[pscustomobject] $renamedProperties
}