Say I have several text files that contain the word 'not' and I want to find them and create a file containing the matches. In Linux, I might do
grep -r not *.txt > found_nots.txt
This works fine. In PowerShell, the following echos what I want to the screen
get-childitem *.txt -recurse | select-string not
However, if I pipe this to a file:
get-childitem *.txt -recurse | select-string not > found_nots.txt
It runs for ages. I eventually CTRL-C to exit and take a look at the found_nots.txt file which is truly huge. It looks as though PowerShell includes the output file as one of the files to search. Every time it adds more content, it finds more to add.
How can I stop this behavior and make it behave more like the Unix version?
Use the -Exclude option.
get-childitem *.txt -Exclude 'found_nots.txt' -recurse | select-string not > found_nots.txt
First easy solution is rename file output extension to another
Related
I have around 3,000 gzip folders that I need to concatenate into one file except for the first line of each file. I also need to have the word "break" in between each file.
Concatenating Files And Insert a Word In Between Files
I asked this a few days ago. I need to do the exact same thing, just taking out the first line. Any help would be appreciated.
For this, you'll need to pipe each file to Get-Content individually and omit the -Raw switch:
Get-ChildItem *gz |ForEach-Object {
$_ |Get-Content |Select-Object -Skip 1
'break'
} |Select-Object -SkipLast 1 |Set-Content -Encoding utf8 allmethods.txt
The Select-Object -Skip 1 command will discard the first line from each file read, and Select-Object -SkipLast 1 will remove the last trailing break from the entire output stream.
While I know how I would do this in PHP, it doesn't make sense to install IIS, install PHP just to get this done.
I have a folder D:\Data that has several subfolders in it. These folders contain files which are backups created with a program that adds a time stamp to the name to allow multiple copies of the file to be backed up.
These files need to be named:
usera.dat
But they are named currently:
usera.dat.17383947323.dat
In PHP, I would load the file name into a string, explode the string on ".", then rename the file using the [0] and [3] elements to rename the file, i.e. without the loop to read the directories:
$filename = $existing_file
$explodename = explode(".",$filename);
$newfilename = $explodename[0] . "." . $explodename[3];
rename($filename, $newfilename);
Does anyone have any recommendation on how to do this with PowerShell or a batch file looping over all the subfolders in D:\Data?
Right now I am manually editing each file removing the extra Unix time stamp.dat part.
Translating this from PHP to PowerShell should be a breeze, let's give it a try:
$files = Get-ChildItem -Filter *.dat.*.dat
foreach($file in $files){
$filename = $file.Name
$explodename = $filename.Split('.')
$newfilename = "$($explodename[0]).$($explodename[3])"
Rename-Item $file.FullName -NewName $newfilename
}
As shown above:
PowerShell does not have an explode() function, but we can use the String.Split() method on any string and get a string array back
. is not a string concat operator in PowerShell, but we can use subexpressions $(...) inside an expandable string.
The Rename-Item cmdlet will take care of renaming
A more PowerShell-idiomatic solution would be to leverage the pipeline though:
Get-ChildItem -Filter *.dat.*.dat | Rename-Item -NewName {$explodename = $_.Name.Split('.');"$($explodename[0]).$($explodename[3])"}
You could also use a regex pattern in place of the Split() method and string concatenation:
Get-ChildItem -Filter *.dat.*.dat | Rename-Item -NewName {$_.Name -replace '^([^\.])\..*\..*\.([^\.])$','$1.$2'}
Or do the concatenation with the -join operator:
Get-ChildItem -Filter *.dat.*.dat | Rename-Item -NewName {$_.Name.Split('.')[0,3] -join '.'}
Whatever you fancy, Get-ChildItem and Rename-Item are definitely the commands you'd want to use here
One-liner in batch from the prompt:
#FOR /r "U:\sourcedir" %a IN (*) DO #FOR %b IN ("%~na") DO #FOR %c IN ("%~nb") DO #IF "%~xc" neq "" ECHO REN "%a" "%~nxc"
Note: echoes the rename command for testing. Remove the echo keyword after testing to execute the rename.
I used u:\sourcedir as a test directory.
Translation: for each filename in the subtree (%%a) take the name part only and assign to %%b, repeat for %%c and if there was no extension part in the result, then do the rename.
Mathias R. Jessen's answer contains many helpful pointers, but it seems that the simpler and more robust approach would be to simply drop the final 2 extensions, assuming that all files in the folder tree have these 2 extraneous extensions:
Get-ChildItem -File -Recurse D:\Data |
Rename-Item -NewName { $_.Name -replace '(\.[^.]*){2}$' }
I need a simple way to create a list of all files in a certain folder. (recursively)
Each file must be in a single line. I also need the file size and the last access date in the same line, separated by a special character.
The output (textfile) should look like this:
c:\folder\file1.txt|400|2012-11-12 15:23:08
c:\folder\file2.txt|200|2012-11-12 15:23:08
c:\folder\file3.txt|100|2012-11-12 15:23:08
c:\folder\sub folder\file4.txt|500|2012-11-12 15:23:08
'Dir' seems not to be an option, because the German Special characters get messed up that way. (öäüß)
Powershell handles the special characters well, but I couldn't make it so that the information for one file ends up in a single line:
get-childitem D:\temp -rec | where {!$_.PSIsContainer} | foreach-object -process {$_.FullName, $_.LastWriteTime, $_.Length}
try this:
get-childitem D:\temp -rec | where {!$_.PSIsContainer} |
select-object FullName, LastWriteTime, Length | export-csv -notypeinformation -delimiter '|' -path file.csv
I am trying a simple replace script to replace text in a app.cofig file. But it just processed and do nothing:
$old = 'Z:\gene'
$new = 'z:\gene\scripts'
Get-ChildItem z:\gene\scripts\Test\App.config -Recurse | Where {$_ -IS [IO.FileInfo]} |
% {
(Get-Content $_.FullName) -replace $old,$new | Set-Content $_.FullName
Write-Host "Processed: " + $_.FullName
}
Any Idea what I am doing wrong. As same script works fine for .txt file
Thanks
App.config is xml formatted but it's a text file as well, it should work the same. My guess is that you have a different values that your working on and they are not hitting. If you rename the file to app.txt does it work ? You might also consider using nant xmlpoke if you are running from nant script.
I have around 400 movies on my hard-disk, but names of those movies contains dots or underscore in between like "wrong_turn.mkv" or "wrong.turn.mkv". I just want to remove these dots or special characters from the file name and keep the extension as it as.
Any Command Line command or Powershell/Python or any other script for windows? Thanks.
If the two files you have reside in the same directory then removing _ from the first file will work, but when you'll try to remove the dot from the second file it will fail cause it'll have the same name as the first one. Maybe that's an edge case, so here's the basic solution:
Get-ChildItem -Filter *.mkv | Rename-Item -NewName {($_.BaseName -replace '\.|_') + $_.Extension}
In PowerShell you can use Rename-Item with a script block that determines the new name.
dir -Recurse -Include *.mkv | Rename-Item -NewName { expression to determine new name }
The expression within the script block can use $_ to reference the current FileInfo object.
More concretely:
dir -Recurse -Include *.mkv | Rename-Item -NewName { $_.Name.Replace('_', ' ') }
Use Rename-Item -WhatIf until you get it right.