我有超过500个文本文件,其中包含纬度,经度和值的列。每个文件都根据年份和月份命名(因此2015年2月是201502_stag.txt,1983年3月是198303_stag.txt等),但此信息不包含在文件本身中。数据看起来像这样:
-140.00 55.00 2
-140.00 54.75 7
-140.00 54.50 3
我想做三件我不知道该怎么做的事情,因为我对使用PowerShell这么新:
1。)将每个文件的标题放入文件中的重复列中(以便年份和月份不会混淆)
2。)删除文件中所有条目,其中lat和long在我感兴趣的区域之外(以最小值和最大值为单位为lat,每个为长),
3.。)将所有这些文件附加在一起
我一直在使用一个教程来试图解决这个问题,而我现在想出了自己的#3。我正在摸不着其余的事情,真的很想学习!
答案 0 :(得分:1)
他也可以做到这一点。为了尝试采用不同的方法,我将输出更改为CSV格式。如果你不需要,那就很容易改变它。
$files = Get-ChildItem "C:\path\*stag.txt"
$files | ForEach-Object{
$filedate = ($_.BaseName).Split("_")[0]
Get-Content $_ | ForEach-Object{
$line = $_ -split "\s+"
New-Object -TypeName PsCustomObject -Property @{
Date = $filedate
Lat = $line[0]
Long = $line[1]
Index = $line[2]
}
}
} | Where-Object{[double]$_.Lat -lt -150 -and [double]$_.Long -lt 54.75} |
Select-Object Date,Lat,Long,Index |
Export-CSV C:\temp\outputfile.csv -Delimiter "`t" -NoTypeInformation
这将使一个目录中的所有文件以" stag.txt"结尾。获取所有内容并将其转换为具有Date,Lat,Long和Index属性的PowerShell对象。我不知道最后一个值是什么,所以我称之为索引。日期来自" _"之前的文件名部分。
然后,由于我们将它作为自定义对象,我们可以使用Where-Object
和我们之前定义的属性。我们将值转换为[double]
以供我们使用数字比较作为字母数字。将其导入Select-Object
以获取正确的顺序并导出到制表符分隔的CSV。
我假设你有PowerShell 1或2.如果你有至少3个,这将更简洁,但我根据你的经验假设。
为了测试,我制作了2个包含以下内容的文件
#198303_stag.txt
-140.00 55.00 2
-150.00 54.75 7
-160.00 54.50 3
#201502_stag.txt
-140.00 58.00 2
-140.00 54.75 7
-140.00 59.50 3
上述代码的输出是
"Date" "Lat" "Long" "Index"
"198303" "-160.00" "54.50" "3"
输出批评
如果你不喜欢这里所做的事情,那么进行一些改变并不是一件容易的事。只是让我知道你在找什么。
答案 1 :(得分:0)
哦,你可以用一个班轮做到这一点。
gci *stag.txt | %{ $f = $_; gc $f | %{ $l=$_ -split '\s+'; if ([float]$l[0] -eq -140.00 -and [float]$l[1] -ge 50) { $_ + ' ' + $f.Name | ac 'merged.txt' } } }
让我们分解。
<#
gci is an alias for Get-ChildItem.
% is an alias for For-Each.
So, for each file in the current dir matching *stag.txt...
#>
gci *stag.txt | %{
# Set $f to the current file object.
$f = $_;
# Get-Content of the file object. For each line...
gc $f | %{
# $l = the line split on one or more spaces.
$l = $_ -split '\s+';
<#
If...
* the first word equals -140, and
* the second word is greater than or equal to 50
Then...
#>
if ([float]$l[0] -eq -140.00 -and [float]$l[1] -ge 50) {
<#
Append-Content to merged.txt
* The unmodified line
* Literal two spaces
* The name of the file
#>
$_ + ' ' + $f.Name | ac 'merged.txt'
}
}
}
虽然此解决方案实际上并未删除原始文件中的任何行,但不相关的行将从merged.txt中排除。
答案 2 :(得分:0)
如果您使用Powershell v3或更高版本($ PSVersiontable),请尝试以下操作:
# specify path to files
$path = "path\to\files"
# thresholds. casting to [double] to use arithmetic operations on them
$latmin = [double]-150
$latmax = [double]-120
$longmin = [double]54.75
$longmax = [double]60
# array for output. cache all results here before export to file, this will minimize IO operations and save some time
$out = @()
# read file by file
foreach ($file in Get-ChildItem -Path $path -Filter "*_stag.txt")
{
# display some progress information
echo "Proceeding file $file"
$filename = $file.BaseName.Replace('_stag','') # or just $file.BaseName
# read contents
$contents = (Get-Content $file.FullName)
# proceed every line, splitting by whitespace (one or more)
# if field delimiter is tab character, replace splitter with '\t+'
# for each line we construct an object and add it to output array
$contents | foreach { $tokens = $_ -split '\s+'; $out += [pscustomobject]@{Date = $filename; Lat = [double]$tokens[0]; Long = [double]$tokens[1]; Num = [int]$tokens[2]} }
}
$out | ft
# exclude unnecessary entries and export to file
$out | where { ($_.Lat -ge $latmin) -and ($_.Lat -le $latmax) -and ($_.Long -ge $longmin) -and ($_.Long -le $longmax) } | Out-File -Encoding utf8 "$path\out.txt"
只需指定文件和条件的路径即可。
编辑:
转换为[double]而不是[int]。感谢Matt。