I'm making a program that changes coordinate values in a .gcd file, i got the single coordinate lines working but the lines with double coordinates aren't. The program is supposed to split the double coordinates up and run them separately as single coordinates. To accomplish this, I sort the form the coordinates could be in to different sections of code to give the right output. Using the length of the string I can sort them easily. While programming this I ran into a simple problem of a
IF " " LEQ " " ()
command. Given values it gets the wrong outcome. A good example is:
#echo off
:start
if "14" LEQ "7" goto next
echo this should be printed
pause
exit /b
:next
echo this shouldn't be printed
pause
exit /b
Removing the " " seems to fix the issue, but I need to compare variables, which can have spaces, justifying the parenthesis. So the question is:
Why does the interpreter get to the wrong outcome, and how can I easily fix this?
Thanks, -Tom
if "14" LEQ "7" goto next
This does a lexicographic string comparison, where "14" < "7" because the first non-equal character 1 < 7.
As you noted, if you drop the quotes the following will do a numerical comparison.
if 14 LEQ 7 goto next
This is consistent with the if /? help:
These comparisons are generic, in that if both string1 and string2 are both comprised of all numeric digits, then the strings are converted to numbers and a numeric comparison is performed.
The quote (which is part of the strings being compared in the first case) is not a numeric digit, so no conversion to numbers is performed, and the comparison is done on the strings by lexical rules.
You also say that but I need to compare variables, which can have spaces. However a numeric value does/can not contain spaces and does not require quotes. On the contrary, once enclosed in quotes it's no longer a numeric value, but a string. So you'll have to decide/distinguish in advance whether you want to compare numerical vs. string values.
Related
My question is similar to this one, but not really.
The issue is that I have variables in my script that will echo/printf control characters directly next to the previous. Unfortunately I have to put spaces between the variables or everything gets misinterpreted, but that's not going to work either, as I can't have spaces between them.
str="25 cents"
one=1
two=2
printf "\x3${one},${two}${str}\x30"\
(without spaces this string messes up)
printf "\x3${one},${two}%s\x30" "${str}" # outputs "5 cents"
So it ends up being either " 25 cents " (wrong), or "5 cents" (wrong x 2)... It should be:
25 cents
I've tried just about everything, escaping the variables, putting them in quotes and no luck. Evidently there's a correct way to handle this that I'm unaware of, so any help is great - thanks.
If what you are trying to do is insert mIRC colour codes into a string -- and you would have made it easier to be helped if you had said so -- then you need to be aware of two things:
The C-style hexadecimal escapes interpreted by Gnu printf have the format \x followed by two hexadecimal digits. (You can use just one digit, but only if the next character is not a hexadecimal digit. So it's better to think of it as always being two digits.) A control-C (character code 3) is written \x03. x30 through \x39 are the character codes for the digits 0 through 9. The translation of the escape code is done by printf, not by the shell, so parameter substitution happens first. So if the value of $one is one, printf "\x3${one}" will be expanded to printf "\x31" by the shell, and then printf will print the digit 1. I presume that is not what you want, since there are obviously much less round-about ways to insert the value of a variable, which don't limit the variable to be a single decimal digit.
Not all printf implementations handle hexadecimal escapes, and not all shells have a built-in printf. So while you can use \x03 with bash, you might find that it is not portable. All printf implementations should handle octal escapes, though, and 3 is still 3 in octal, but now you need three digits: \003.
The mIRC colour codes have the form control-C followed by up to two numbers separated by a comma. These numbers have a maximum of two digits, and if the next character after the colour code is a digit, you must use the two-digit form. (Coincidentally similar to the hex escape codes above, but it is truly just a coincidence.) So if you wanted the text 25 with foreground colour 3 and background colour 1, you would need to send ^C1,0225^C; if you sent ^C1,225^C, that would be interpreted as foreground colour 1 and background colour 25 (which is not a valid colour code), with the text being 5.
This is mentioned in the mIRC documentation linked above:
Note: if you want to color text that begins with numbers, this syntax requires that you specify the color value as two digits.
So a better printf invocation might be:
printf "\003%02d,%02d%s\003" "$one" "$two" "$str"
Note: It is, of course, possible that my guess about what string you are seeking to produce is completely wrong; it is just a guess based on an off-hand comment which was not deleted. If so, and if you are serious about getting your question answered, I strongly suggest you provide a clearer explanation of precisely what byte-string you are attempting to produce with your printf statement.
My line of code is:
SET /A 327761=%RANDOM% * 1000 / 32768 + 1
And I'm just getting a missing operator error. I don't see how this could be and other questions on here don't help.
Because nobody decided to post an answer, here it is, thanks to #SomethingDark
You can't have just numbers as variable names. So I added a character C to the start of the variable.
While it is a bad idea to name a variable starting with a number, the usual problem araises when trying to retrieve the value, not when you set it. That is, there is not any problem in doing
set "1234=some value"
You will have later problems retrieving the value because %1234% is parsed as %1 (first argument to batch file) followed by the string 234%
But as said, you can set the value. So, why something like set /a "1234=1+1" raises an error?
The reason is that the commands in cmd are first parsed to determine the command to execute, but in some cases, once the command has been identified, the rest of the work is delegated to a command specific parser. for command is one example of this behaviour, but set /a also has its own parser.
This set /a parser does not only handle the var=value syntax. You can also do things like
set /a 123+123
to retrieve the result of the calc not storing it anywhere.
The set /a parser handles its parameters as a sequence of numeric/arithmetic/logic/bit/assignment operands/operators. The = is just an assignment operator, and this operator needs the operand on its left side to be a variable name.
The problem is that the set /a parser gives precedence to the numeric operands over the variable names: if it starts with a number, it is a number operand. In your case, set /a 327761=...., the 327761 literal is handled as a numeric operand, not as a variable name, and the assignment operator can not assign a value to another value.
I'm working with a batch file and I was wondering, why do some variables have double quotes around them and others don't, for example?
SET "keePass=%USERPROFILE%\KeePass\KeePass-2.31\KeePass.exe"
but this:
SET name="bob"
Why the double quotes in the first one, but not the second?
...to provide the conclusion at the beginning:
Supposing you have got the command extensions enabled (which is the default setting of the Windows command prompt cmd), the best practice is to use the following set syntax:
set "VAR=value"
(The command extensions can be enabled/disabled by cmd (type cmd /? in a command prompt window for help) or, within batch files only, by setlocal (type setlocal /? for details).)
At first, let us take a look at the standard syntax mentioned in the help text, that appears when typing set /? (or help set) in a command prompt window:
set VAR=value
This assigns the string value to the variable VAR obviously.
The good thing of this syntax is:
it also works when the command extensions are disabled;
the variable value is not surrounded by quotation marks (supposing value does not contain such on its own), so there is only one place to take care of them, namely during variable expansion (like %VAR% or "%VAR%", depending on the situation at hand; this is particularly useful when combining strings like constant_%VAR% or "constant_%VAR%", which will be expanded to constant_value or "constant_value", respectively, so you always have full control over the placement of the quotation marks; if the value contained the enclosing "", constant_%VAR% would expand to constant_"value", which might probably not be the string you want to have);
But there might occur some problems:
any (invisible) trailing white-space becomes part of the string value, so if the command line is followed by a single SPACE character, VAR will carry the value valueSPACE;
when you concatenate this command with another command, like set VAR=value & echo Text, the SPACE before the & character becomes part of the value; you could of course write set VAR=value&echo Some text, but this was quite difficult to read;
if value contains special characters, like ^ & ( ) < > |, you might run into problems; for example, set VAR=1&2 will assign 1 to VAR, then an error will arise, because & separates two commands and 2 is not a valid one;
The syntax of the second example in your question is quite similar:
set VAR="value"
This assigns the string "value" to VAR, so the quotation marks are included in the value.
The advantages are:
it also works when the command extensions are disabled;
special characters (like ^ & etc.) in value do not cause any trouble because of the "";
But still:
the quotation marks become part of the value, which may be disturbing in numerous situations;
unwanted trailing white-spaces (after the last ") still become part of the string value;
again when concatenating this command with another command using &, you have to omit spaces around the ampersand;
Now, let us check out the syntax of the first example in your question:
set "VAR=value"
This assigns value to VAR. Since the quotation marks are placed around the entire assignment expression, they are removed before the assignment is actually accomplished.
This has got several advantages:
the quotation marks do not become part of the variable value;
any (unintended) trailing white-spaces do not become part of the variable value;
you can concatenate it with another command using SPACE&SPACE without any unwanted spaces being appended to the value;
special characters (like ^ & etc.) in value are no problem;
But there is one issue:
the command extensions need to be enabled for this syntax to work; otherwise, an error arises;
Finally, you could also combine the above syntaxes, if you do want the quotation marks to become part of the variable value (although I do not recommend that):
set "VAR="value""
This assigns "value" to VAR.
Advantages:
unwanted trailing white-spaces (after the last ") do not become part of the variable value;
you can concatenate it with another command using SPACE&SPACE without any unwanted trailing spaces in the value;
Disadvantages:
the quotation marks become part of the value, which may be disturbing in numerous situations;
the command extensions need to be enabled for this syntax to work; otherwise, an error arises;
special characters (like ^ & etc.) in value may cause problems; this is because of the way the command parser works: as soon as the first " is encountered, any special characters are no longer recognised, they are treated as literal characters; after the next ", special character recognition becomes re-activated, and so on; regard that this is also true in case value itself contains any quotation marks on its own;
Side Note:
Never put spaces around the equal-to sign in a set command line, because they will become part of the variable name and/or value. For instance, the command lines
set VAR = value
and
set "VAR = value"
both assign the string value SPACEvalue to a variable named VARSPACE.
I'm looking for a random function in batch that I can tack onto the beginning of a filename. I'm creating several thousand symbolic links and I intend to randomize the sorted results by appending a random number to the beginning of the filename.
I have used this function in my nested for loops (iterating through all files in all subdirs):
mklink "%LINKDIR%\%random%%%f" "%%f"
It returns almost what I want. Unfortunately each symbolic link has the same starting random number. Is there anyway to reseed the %random% value?
Use delayed expansion. I.e. put
setlocal enabledelayedexpansion
at the start of your batch file and then use !random! instead of %random%. See help set for a detailed explanation of the topic.
The point here is that %random% gets expanded when the for loop is parsed; thus for subsequent iterations (i.e. when the loop is actually run) there is no variable there anymore, just the value. This is fixed by delayed expansion.
I need to validate a password it should have the following requirements:
The password should have at least 8 characters
The password should have at least 1 uppercase, 1 lowercase, 1 number, and 1 special character
The password should have no continues character(ex. 12345 or abcd)
Please help me to do this.. any suggestions will be a big help.
Thank you
Iterate string. If the character is uppercase then set bool isUppercase to true... If character is special character then set bool isSpecialCharacter to true. If the difference between this character and previous character is 1 then you have two consecutive characters, and you can stop iterating then (set bool haveConsecutiveCharacters to true).
The thing about consecutive characters is that if one of them is special character then they are not really consecutive (consider 'Z' and '[' that are next to each other in ASCII table).
After iterating check if all booleans are true and there are no consecutive characters.
If you really want a regexp for this, you'll have to use assertions :
/^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[\W\D\S]).{8,}$/
Now, the hard part is no consecutive characters. I suggest doing it with a loop instead of doing it with a regexp (actually, I don't know how to do it with a regexp).