GREP equivalent for Windows OS through Python script - python-3.x

Please, can someone help me with an alternative for Windows to the following command:
Linux Version:
find Win32_EXE -type f -name '*.json' -exec grep --files-with-match -i 'dbtool' '{}' ;
Windows version:
FIND /i "dbtool" \Win32_EXE*.json
Problem: The windows syntax lacks an option letting me specify that I want a result returned on the first match.

In python I would use a recursive glob:
from glob import iglob
def search(file):
with open(file) as fo:
for line in fo:
if "dbtool" in line.lower():
return True
return False
for file in iglob("Win32_EXE/**/*.json", recursive=True):
if search(file):
print(file)
but I think in general I wouldn't use Python - other solutions are probably faster/better.
e.g. Powershell
get-childitem -recurse *.json | where-object { select-string -quiet -pattern "dbtool" -path $_ }
or, if you can install ripgrep, that works well.
rg -l -g "*.json" -i dbtool Win32_EXE

This will search for *.json files and search them for the string dbtool. Change the PUSHD directory to your search directory.
PUSHD "C:\src\t"
FOR /F "delims=" %%A IN ('DIR /S /B /A:-D "*.json"') DO (
FIND /I "dbtool" "%%~A"
)
POPD

Related

A bash script to unrar all files in a sub directory in linux

I'm on Ubuntu server 18.04.
My main goal is to run a script from a parent directory which unrars all the files inside all sub directories of the parent directory.
I have also installed apt install unrar and it is located at "/usr/bin/unrar".
This is what I have come up with till now. But it does not seem to work:
for dir in 'pwd/*/'
do
dir=${dir%*/}
cd dir
for file in dir/*/
do
"/usr/bin/unrar" x dir/*.r* dir/
done
I've found a working script for Windows which uses 7zip here
Here's a starting example; adjust pattern and echo statements as needed:
#!/bin/bash
pattern='*/*.rar'
archives=($pattern)
if [[ "${archives[#]}" == "$pattern" ]]; then
echo NONE 1>&2
exit
fi
for rpath in "${archives[#]}"; do
dir=${rpath%/*}
rar=${rpath##*/}
pushd "$dir" > /dev/null
echo -e "\ndir: $dir"
echo unrar args "$rar"
popd > /dev/null
done
If you just want to unrar every rar file in the directory where it was found, find can do that directly. It takes some getting used to, but it's well worth learning.
find . -name '*.rar' -execdir unrar {} \;
Briefly, -execdir says to run the stuff up to \; on each found file in the directory where it was found; the {} placeholder gets replaced with the file name.
find . -name '*.rar' -execdir unrar {} \;
This didn't work for me.
I changed it to this and it worked.
find . -name '*.rar' -execdir unrar e -r {} \;

Delete line from all the files in a folder with string 'Generation'

I want to delete a line with string 'Generation' in all the files under a folder named KCG. I tried the following in Windows OS command prompt:
sed -i '/Generation/d' file
But got the following error message:
sed: can't read file: No such file or directory
Next I tried:
sed -i '/Generation/d' airport_related_altitudes_derived_data.c
This worked, but I do not want to enter the filenames of all the files in the folder each time. Is there a command to recursively look for the string in all the files under the folder?
Try this:
find . -type f -exec sed -i '/Generation/d' {} \;
That will recursively find all files ("-type f") under the current directory (".") and call "sed -i '/Generation/d'" on each file ("{}").
A windows way to enumerate files of a pattern/file type in current folder.
#Echo off
For %%A in (*.c) Do sed -i '/Generation/d' %%A
Recursive from a start path
For /r "X:\start\path" %%A in (*.c) do sed -i '/Generation/d' %%A
A pure batch way to drop lines containing words from a file is using find /v or findstr /v but requires a different output file name, no inplace editing.
#Echo off
for %%A in (*.c) do findstr /vi "Generation" "%%~A" >"%%~dpnA_new%%~xA"
what creates new files with a appended _new before the extension.
It's of course possible to rename the old to .bak and write the changed version to the original name.

Find file, convert it and leave in orginal directory in bash

I have a simple script to convert .docx to .pdf:
for d in $(find /home/kfalasz/Pulpit/konwersjapdf -maxdepth 3 -name "*.docx")
do
soffice --headless --convert-to pdf $d
rm $d
echo $d
done
it works good but all converted files are in /home/kfalasz/Pulpit/konwersjapdf and I would like to leave them in orginal directory for example file /home/kfalasz/Pulpit/konwersjapdf/a/plot.docx convert to .pdf and leave in /home/kfalasz/Pulpit/konwersjapdf/a/plot.pdf and actually it leaves file in /home/kfalasz/Pulpit/konwersjapdf/plot.pdf.
How to keep the orginal file tree?
Using GNU Tools
GNU find itself can do what you want:
find /home/kfalasz/Pulpit/konwersjapdf -maxdepth 3 -name "*.docx" \
-execdir soffice --headless --convert-to pdf '{}' ';' \
-delete
-execdir causes each command to be run directly in the location where the file was found.
Because -exec and -execdir only pass on true when the command in question succeeds, this will only delete files which soffice was able to convert.
On All POSIX Platforms
As an alternative that works on all versions of find, not only GNU releases, consider:
find . -maxdepth 3 -name "*.docx" -type f -exec sh -c '
for p do
(cd -- "${p%/*}" || exit; exec soffice --headless --convert-to pdf "${p##*/}") \
&& rm -f -- "$p"
done' _ {} +
Here, the subshell created by the ( scopes the effect of cd; the exec then consumes that subshell, ending the scope at hand.
You can include --outdir with your command:
soffice --headless --convert-to pdf --outdir "${d%/*}" $d
Where ${d%/*} trims the last bit of the file name off and leaves the basename of the directory.
You could alternatively use pushd and popd to change the cwd there, but personally I'd prefer the flag option.
I don't have soffice installed, but it sounds from OP's answer, appropriate flag is the way to go here. Here is a pushd popd version using find
$ find . -maxdepth 3 -name "*.docx" | \
xargs -I {} bash -c 'p="{}";
pushd $(dirname "$p") >/dev/null;
bp=$(basename $p);
soffice --headless --convert-to pdf "$bp";
popd>/dev/null;'

How do I recursively unzip nested ZIP files?

Given there is a secret file deep inside a nested ZIP file, i.e. a zip file inside a zip file inside a zip file, etc...
The zip files are named 1.zip, 2.zip, 3.zip, etc...
We don't know how deep the zip files are nested, but it may be thousands.
What would be the easiest way to loop through all of them up until the last one to read the secret file?
My initial approach would have been to call unzip recursively, but my Bash skills are limited. What are your ideas to solve this?
Thanks Cyrus! The master wizard Shawn J. Goff had the perfect script for this:
while [ "`find . -type f -name '*.zip' | wc -l`" -gt 0 ]; do find -type f -name "*.zip" -exec unzip -- '{}' \; -exec rm -- '{}' \;; done
Here's my 2 cents.
#!/bin/bash
function extract(){
unzip $1 -d ${1/.zip/} && eval $2 && cd ${1/.zip/}
for zip in `find . -maxdepth 1 -iname *.zip`; do
extract $zip 'rm $1'
done
}
extract '1.zip'
Probably not the cleanest way, but that should do the trick:
#!/bin/sh
IDX=1 # ID of your first zip file
while [ 42 ]
do
unzip $IDX.zip # Extract
if [[ $? != 0 ]]
then
break # Quit if unzip failed (no more files)
fi
if [ $IDX -ne 1 ]
then
rm $IDX.zip # Remove zip to leave your directory clean
fi
(( IDX ++ )) # Next file
done
Checkout this java based utility nzip for nested zips.
Extracting and compressing nested zips can be done easily using following commands:
java -jar nzip.jar -c list -s readme.zip
java -jar nzip.jar -c extract -s "C:\project\readme.zip" -t readme
java -jar nzip.jar -c compress -s readme -t "C:\project\readme.zip"
PS. I am the author and will be happy to fix any bugs quickly.
Here is a solution for windows assuming 7zip is installed in the default location.
#echo off
Setlocal EnableDelayedExpansion
Set source=%1
Set SELF=%~dpnx0
For %%Z in (!source!) do (
set FILENAME=%%~nxZ
)
set FILENAME=%FILENAME:"=%
"%PROGRAMFILES%\7-zip\7z.exe" x -o* -y "%FILENAME%"
REM DEL "%FILENAME%"
rem " This is just to satisfy stackoverflow code formatting!
For %%Z in (!source!) do (
set FILENAME=%%~nZ
)
for %%a in (zip rar jar z bz2 gz gzip tgz tar lha iso wim cab rpm deb) do (
forfiles /P ^"%FILENAME%^" /S /M *.%%a /C "cmd /c if #isdir==FALSE \"%SELF%\" #path"
)
This has been adapted from here https://social.technet.microsoft.com/Forums/ie/en-US/ccd7172b-85e3-4b4a-ad93-5902e0abd903/batch-file-extracting-all-files-from-nested-archives?forum=ITCG
Notes:
The only way to do variable modification using the ~ modifiers is to use a dummy for..in loop. If there is a better way please edit.
~nx modifies the variable to make it a full path+file name.
~dpnx also does the same thing to %0 i.e. gets the full path and filename of the script.
-o* in the 7zip command line allows 7zip to create folder names without the .zip extension like it does when extracting with a right click in the gui.
~n modifies the variable to make it a filename without an extension. i.e. drops the .zip
Note that the escape character (for quotes) in FORFILES /P is ^ (caret) while for the CMD /C it is \. This ensures that it handles path and filenames with spaces also recursively without any problem.
You can remove the REM from the DEL statement if you want the zip file to be deleted after unzipping.

Equivalent for find -o (shell) in .cmd

Can someone tell me the .cmd equivalent command for the shell command find -o -samefile ?
I am trying to loop inside folders to copy files into a different location.
My original shell script is :
for qapi_file in find . -type d -iname qapi_export -o -samefile qapi/common -o -samefile core/api; do cp -p $qapi_file/qapi*.h include/qapi/
I have tried doing this:
FOR /d %%i IN ( DIR -i qapi_export qapi\common\ core\api) do (xcopy /O %i%\qapi*.h include\qapi)
this does not work as I expect it to. If I use for /d , it loops once and returns no files to copy. On the other hand if I use for /r the for loop becomes endless and I am unable to break the loop (I tried using goto :eof for this but it gives an error - goto was unexpected here)
I am pretty new to this and am unsure how to proceed further. I would appreciate any input in this regard
Using %%i instead of %i% and looping through all subdirectories with /r will do the trick:
for /r . %%i in (.) do (
xcopy /y/o %%i\qapi_export\qapi*.h include\qapi
xcopy /y/o %%i\qapi\common\qapi*.h include\qapi
xcopy /y/o %%i\core\api\qapi*.h include\qapi
) >nul

Resources