How to replace variable text in file by using Windows .cmd? - windows

I have .ini file and there is a line with
HOST='pc-name'
fragment. But it can be something else instead of pc-name. HOST='random' or HOST='welcome' for example. I need to find it and replace with HOST='%COMPUTERNAME%' where %COMPUTERNAME% is real computer name where this .cmd file is running. I've only found how to replace static things, so the problem is to detect this fragment with random value. And = is interpreted as assignment operation but I need it as simple text symbol.
P.S. I need to do it with .cmd file.

A tool to search/replace files/pipe lines/blocks: 1 command line
Use msr.exe in my open project https://github.com/qualiu/msr tools directory.
For your case: (Remove -R to preview replacing result; Add -K to backup)
Replace any content HOST=.* to HOST=%COMPUTERNAME% :
msr -p my.ini -t "^(HOST)=.*" -o "$1=\%COMPUTERNAME\%" -R
More general: ignore case, white-spaces:
msr -p my.ini -it "^(HOST)\s*=.*" -o "$1=\%COMPUTERNAME\%" -R
Additionally:
Use msr-Win32.exe if your windows is 32-bit.
Recursively replace in multiple paths and files:
msr -rp directory1,dirN,file1,fileN -f "\.ini$" -it "^(HOST)\s*=.*" -o "$1=\%COMPUTERNAME\%" -R

You can use tools like Notepad++ to open the .ini file.
You can then use a regular expression search to find such strings. For example, you can use HOST='.*' as a search expression with Search mode as "Regular Expression" in Notepad++. This will search for the pattern HOST='any value' and then you can replace it with HOST='%COMPUTERNAME%'
Using CMD, you can use
findstr "HOST='.*'" < _place your .ini file name_ >.ini to find all strings which match the pattern and then replace them

If you can assume that HOME= will always start in the first column and that the only thing after it could be a string enclosed in apostrophes, you could do something like.
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
FOR /F "usebackq tokens=*" %%s IN (`TYPE "thefile.txt"`) DO (
SET "STR=%%~s"
IF "!STR:~0,6!" EQU "HOME='" (
ECHO HOME='newsetting'
) ELSE (
ECHO %%~s
)
)

If you would have a file with one or more lines containing variables as
HOST='%COMPUTERNAME%'
as you indicate halfway in your post, then you could easily have them replaced as follows. I'm assuming your file is called inputfile and your output goes to outputfile.
for /F "tokens=*" %%I in (inputfile) do call echo %%I>> outputfile
Notes:
The above command should be inside a cmd script, otherwise one should use %I instead of %%I if one wants to run it from the cmd prompt directly.
The "call" statement makes sure that the variables are converted
into their values. Without it, they would remain as variables.
Empty lines get discarded, not sure if there is a way to avoid that.
Make sure you don't put any spaces before the ">>" otherwise they will be there in your output file.

Related

Script to move all files starting with the same 7 letters in a different folder named after first 7 chars of its future content

All files are in a directory (over 500 000 files), named in the following pattern
AR00001_1
AR00001_2
AR00001_3
AR00002_1
AR00002_2
AR00002_3
I need a script, can be both batch or unix shell that takes everything with AR00001 and moves it into a new folder that will be called AR00001, and does the same for AR00002 files etc
Here's what I've been trying to figure out until now
for f in *_*; do
DIR="$( echo ${f%.*} | tr '_' '/')"
mkdir -p "./$DIR"
mv "$f" "$DIR"
done
Thanks
// Update
Ran this in the CMD
for %F in (c:\test\*) do (md "d:\destination\%~nF"&move "%F" "d:\destination\%~nF\") >nul
Seems to be almost what I wanted, except that it does not take the first 7 characters as a substring but instead creates a folder for each file :/ I'm trying to mix it with your solutions
#echo off
setlocal enabledelayedexpansion
for %%a in (???????_*) do (
set "x=%%a"
set "x=!x:~0,7!"
md "!x!" >nul
move "!x!*" "!x!\" 2>nul
)
for every matching file do:
- get the first 7 characters
- create a folder with that name (ignore error message, if exist)
- move all files that start with those 7 characters (ignore errormessages, if files doesn't exist (already moved))
The following achieves the desired effect and checks for non-existence of the target directory each time before creating it.
#echo off
setlocal ENABLEDELAYEDEXPANSION
set "TOBASE=c:\target\"
set "MATCHFILESPEC=AR*"
for %%F in ("%MATCHFILESPEC%") do (
set "FILENAME=%%~nF"
set "TOFOLDER=%TOBASE%!FILENAME:~0,7!"
if not exist "!TOFOLDER!\" md "!TOFOLDER!"
move "%%F" "!TOFOLDER!" >nul
)
endlocal
In the move command, by moving only the current file rather than including a wildcard, we ensure that we're not eating up file names that might be about to appear the next time around the loop. Keeping it simple, assuming that efficiency is not of prime importance.
I'd recommend prototyping by creating batch files (with a .bat or .cmd extension) rather than trying to do complex tasks interactively using on one-liners. The behaviour can be different and there are more things you can do in a batch file, such as using setlocal to turn on delayed expansion of variables. It's also just a pain writing for loops using the %F interactively, only to have to remember to convert all those to %%F, %%~nF, etc. when pasting into a batch file for posterity.
One word of caution: with 500,000 files in the folder, and all of the files having very similar prefixes, if your file system has 8.3 directory naming turned on (which is often the default) it is possible to run into problems using wildcards. This happens as the 8.3 namespace gets more and more busy and there are fewer and fewer options for ways the file name can be encoded in 8 characters. (The hash table fills up and starts overflowing into unexpected file names).
One solution is to turn that feature off on the server but that may have severe implications for any legacy applications. To see what the file looks like in 8.3 naming scheme, you can do, e.g.:
dir /x /p AR*
... which might give you something like (where the left hand name is the one converted to 8.3):
ARB900~1.TST AR15467_RW322.tst
AR85E3~1.TST AR15468_RW322.tst
ARDDFE~1.TST AR15469_RW322.tst
AR1547~1.TST AR15470_RW322.tst
AR1547~2.TST AR15471_RW322.tst
...
In this example, since the first two characters seem to be maintained, there should be no conflict.
So for example if I say for %a in (AR8*) do #echo %a I get what might at first seem to be incorrect:
AR15468_RW322.tst
AR18565_RW322.tst
AR20376_RW322.tst
AR14569_RW322.tst
AR17278_RW322.tst
...
But this is actually correct; it is all the files that match AR8* in both the long file name and short file name formats.
Edit: I am aware in retrospect that this solution looks very similar to Stephan's, and I had browsed through the existing answers before starting work on my own, so I should credit him. I will try and save face by pointing out a benefit of Stephan's solution. Its use of wildcards should circumvent any 8.3 naming issue: by specifying the wildcard as ???????_*, it only catches the long file names and won't match any of the converted 8.3 file names (all of which are devoid of underscores in that position). Similarly, a wildcard such as AR?????_* would do the same.
With bash, you'd write:
for f in *; do
[[ -d $f ]] && continue # skip existing directories
prefix=${f:0:7} # substring of first 7 characters
mkdir -p "$prefix" # create the directory if it does not exist
mv "$f" "$prefix" # and move the file
done
For the substring expansion, see https://www.gnu.org/software/bash/manual/bash.html#Shell-Parameter-Expansion -- this is probably the bit you're missing.

Copying files with specific extension from a list (text file) of directories

I have a text file with list of certain directories that I want to copy *.xlsx files from them to another directory.
This is how the the text file (list.txt) is arranged:
PT_NAK01, PT_NAK04, PT_NAK05, PT_JAR03
What I have so far:
#echo off
set main_folder="\\internal.company.com\project folder\"
set my_folder="C:\_M__\files"
for /f "tokens=*" %%i in (list.txt) DO (
xcopy "%main_folder%\%%i" "%my_folder%"
)
So the folders that I want to look into would be \\internal.company.com\project folder\PT_NAK01 etc.
What I don't know is how to pass the specific extension *.xlsx to this command.
Note: I haven't used /S switch with xcopy deliberately because I do not want the files in the sub-directories.
P.S. Solutions in powershell or cygwin work for me as well.
This is a cygwinshell answer (bash is an advanced shell that should be reserved for when standard Posix shell (/bin/sh) is insufficient). Note that slashes are reversed intentionally.
I see the format in your list.txt is delimited with commas and whitespace. I am going to assume that this is literal and the reason none of what you've tried so far works. Therefore, I am parsing it with the explicit assumption that comma and then space (, ) is a delimiter and that there is no way to escape them (e.g. if you have a file named apples, oranges.txt then my code would erroneously parse files named apples and oranges.txt).
#!/bin/sh
main_folder="${1:-//internal.company.com/project folder}"
my_folder="${2:-c:/_Masoud/files}"
cd "$main_folder" || exit $?
IFS=', ' find $(cat list.txt) -maxdepth 1 -name \*.xlsx |while IFS= read xlsx; do
mkdir -p "$my_folder/${xlsx%/*}"
cp -a "$xlsx" "$my_folder/$xlsx"
done
I've done some extra work for you to make this more abstract. $main_folder is taken from your first argument (a missing argument will default to //internal.company.com/project folder) and $my_folder is taken from your second argument (if missing, it defaults to c:/_Masoud/files). Don't forget to quote your command-line arguments if they contain spaces or interpretable characters.
After determining your source and destination, I then try to change directories to the source directory. If this fails, the script will stop with the same exit code.
Now for the loop. I've changed the Input Field Separator ($IFS) to be the comma and space (, ) we talked about earlier and then glued the contents of list.txt into its arguments, followed by the requirement of being one level deep (to include PT_NAK05/foobar/baz.xlsx, use -maxdepth 2 or just remove that clause altogether to view the file tree recursively), followed by the requirement of a name matching *.xlsx (this is escaped because your shell would otherwise assume you're talking about the local directory). The output of this is then read into a loop line by line as $xlsx. We recreate the target's parent directory in the new target destination if it's not already present, then we copy the file to that location. cp -a preserves permissions and time stamps.
One thing that made an error in my example was how I set the text file with the folder names. It should be set up with carriage return as separator instead of comma-separated entries.
PT_NAK01
PT_NAK04
PT_NAK05
etc.
With that, this batch-file (in reference to MatSnow's and shellter's comments) works fine for the purpose of the question.
#echo off
set main_folder="\\internal.company.com\project folder\"
set my_folder="C:\_M__\files"
for /f "tokens=*" %%i in (list.txt) DO (
xcopy "%main_folder%\%%i\*.xlsx" "%my_folder%"
)
Note: If you want to type this directly into the command line, you don't need double % for the variables.

How to Find and Replace file content in batch script

For example I have the file sample.txt. This file contains:
1111101
2222203
3333303
44444A1
55555A1
66666A1
Now, I want to replace user defined specific pattern. For example I have other file where use defines what he want to replace with. Example the file name is replace.txt. This file contains 2 Columns, first column for the pattern and the 2nd column for the text to be replace.
Example:
replace.txt
2222203 2222203ADD
55555A1 55555A1SUB
Now, when the batch file has been executed, I would like the file sample.txt to have a contents like this:
1111101
2222203ADD
3333303
44444A1
55555A1SUB
66666A1
Also is it possible to have a "space" as part of the text to be replace(column 2?
You may use FindRepl.bat program that is a Batch-JScript hybrid application that perform these replacements in a very efficient way via regular expressions; it uses JScript language that is standard in all Windows versions from XP on. In the basic use of FindRepl.bat you redirect the input file to it and place two strings as parameters, a "search" string and a "replacement" string. For example:
< sample.txt FindRepl.bat "2222203" "2222203ADD"
Previous command will replace all 2222203 strings in the file by 2222203ADD. In order to perform the replacement of several strings, you may include several alternatives in both the search and replacement strings separated by a pipe character (this is called alternation), and include the /A switch to select this feature; for example:
< sample.txt FindRepl.bat "2222203|55555A1" /A "2222203ADD|55555A1SUB"
If you want to define the set of replacements in a separated file, you just need to load the strings from the file, assemble the alternations in two variables and use they in FindRepl preceded by an equal-sign to indicate that they are variables, not literal strings. If you want that the strings may have spaces, then you must use a different character to separate the search and replace parts in the file. For example, if you use a colon in replace.txt file this way:
2222203:2222203 ADD
55555A1:55555A1 SUB
Then the Batch file below solve your problem:
#echo off
setlocal EnableDelayedExpansion
set "search="
set "replace="
for /F "tokens=1,2 delims=:" %%a in (replace.txt) do (
set "search=!search!|%%a"
set "replace=!replace!|%%b"
)
set "search=!search:~1!"
set "replace=!replace:~1!"
< sample.txt FindRepl.bat =search /A =replace
You may download FindRepl.bat and review an explanation of its use from this site; you must place it in the same folder of previous program or, better yet, in a folder included in PATH variable.

Word Sorting in Batch

Right let me rewrite this try to make it more clear.
Picture added to make this even clearer:
I have two files
File 1, contains words.
file 2, contains commands.
I need to put words from FILE 1
into FILE 2
I cannot copy-paste them one by one, because there is a LOT of words in FILE 1
File 1 is listed in alphabetical order (by first letter)
File 2 the command does not change
The issue is getting words from file 1 into file 2
but they have to be moved into quotes " " in file 2
so a script that could for example..
Take apple from file 1 and move it between quotes admin.executemotecommand "apple"inside file 2 as it goes down the list keeping the words in order as they move them across.
This could perhaps be done the same way around in which, the script writes the command in front of the words in file 1 as it goes down file 1's list
Is this even possible? I've never seen this done anywhere else and completely clueless if batch is even the right language for it.
The question is a little confusing, but based on your responses in the comments my understanding is that you don't necessarily need the script to edit a preexisting file 2, because you're repeating the same command(s) for each word, so the script can just create a new file based on the words in file 1.
You can do it at the prompt like this:
FOR /F %a IN (words.txt) DO ECHO admin.executeremotecommand "%a" >> commands.txt
The original version of the question indicated that you want more than one command for each word. I take it you changed that in order to simplify that question, and figured you'd just run the script once for each command? However, it's quite simple to have it produce more than one command for each word:
FOR /F %a IN (words.txt) DO (ECHO first.command "%a" & ECHO second.command "%a") >> commands.txt
In a batch file, you'd do it this way:
#ECHO OFF
FOR /F %%a IN (words.txt) DO (
ECHO first.command "%%a"
ECHO second.command "%%a"
) >> commands.txt
BTW, in the code in some of your comments, you surrounded the variable with %'s (%A%). That's incorrect; it would evaluate to the value of %A followed by a literal %. Surrounding with %'s is used only for environment variables. (Note that the %'s around environment variables do not get doubled in a batch file. For example, to get the current date, use ECHO %date% both at the prompt and in a batch file.)

Why is this batch file producing extra, unexpected, unwanted characters?

I'm trying to use the following batch script to concatenate some files together:
copy NUL bin\translate.js
for %%f in (source\Libraries\sprintf.js, source\translate-namespace.js, source\util.js, source\translator.js, source\translate.js) do (
type %%f >> bin\translate.js
echo. >> bin\translate.js
)
However, when I do this, an extra character seems to be printed at the end of each file. When I view the file in ASCII, it is interpreted as these three characters:

Why is this happening? What can I do to fix it?
The  looks like a unicode byte order mark. Is it possible to start with files that are stored without the byte mark? I am not aware of any command line commands that can remove the mark.
The DOS copy command works like the UNIX cat command. That is, you can list multiple source files and one destination file, seperated with + signs.
copy source\Libraries\sprintf.js+source\translate-namespace.js bin\translate.js

Resources