Reputation: 6127
I'm having a problem with what seems like it should be a fairly basic piece of a script.
ECHO !url1! >> !hostsfile! && ECHO Successfully added !url1! to file. || 2>&1>NUL && ECHO Unable to write !url1! to file. && GOTO :FAIL
It's a conditional that tries to write a URL to a given file, and if access to that file is denied, prints an error message. Unfortunately, CMD also generates its own error message, so at the moment, as output, I'm getting the default error "Access denied" followed by my own "Unable to write www.url.com to file."
I've tried without luck to pipe the default error message to NUL, but even with all my reading up on it, my knowledge on how piping works and the syntax for it is still sparse, and I'm not getting anywhere.
Also, as an aside: is there any way to split that line to be more manageable without causing errors?
Trying stuff like:
ECHO !url1! >> !hostsfile! && ECHO Successfully added !url1! to Hosts file.
|| 2>&1>NUL && ECHO Unable to write !url1! to Hosts. && GOTO :FAIL
or
ECHO !url1! >> !hostsfile! && ECHO Successfully added !url1! to Hosts file. ||
2>&1>NUL && ECHO Unable to write !url1! to Hosts. && GOTO :FAIL
...results in "unexpected character" errors.
NB. Exclamation marks are being used for variables because of delayed expansion.
Upvotes: 4
Views: 852
Reputation: 34949
There are several issues:
2>&1>NUL
is invalid redirection syntax, you cannot concatenate multiple redirection operators like that. I assume you want to redirect the STDERR stream to the nul
device, so it should read 2>nul
or 2> nul
.2>&1>NUL
, but there is no command.echo
command does actually not produce the error message Access is denied.
, it is caused by a failed redirection. Therefore you must enclose the redirected echo
command in parentheses in order to be able to suppress the error message by the 2> nul
redirection.echo
command itself does not set the ErrorLevel
pseudo-variable nor the exit code1. However, a failed redirection (<
, >
, >>
) sets the exit code, which is what you are interested in.goto
command is only executed in the ||
branch, so you should put that entire portion in between parentheses.echo Text > file.ext
, the SPACE in between Text
and >
is also output. To avoid that, either simply remove it like echo Text>file.ext
, place a pair of parentheses around the echo
command like (echo Text) > file.ext
, or revert the syntax like > file.ext echo Text
(which is the way I prefer as it is the most general one).echo Text & goto :LABEL
, the SPACE in front of &
is output as well. To avoid that, remove it, or enclose the echo
part within parentheses.cmd
that the two lines belong together. Line continuation is done by ending a line with a caret ^
, so the next one is concatenated2. The next line should be preceded by (at least) a SPACE. Alternatively, parenthesised blocks of code may span multiple lines, so you could also end the first line like ... || (
and have the next line like ... )
for them to be considered as a single command line.Here is the fixed code:
(>> "!hostsfile!" echo !url1!) 2> nul && (echo Successfully added !url1! to file.) || (echo Unable to write !url1! to file.& goto :FAIL)
Or (using line continuation):
(>> "!hostsfile!" echo !url1!) 2> nul && (echo Successfully added !url1! to file.) ^
|| ((echo Unable to write !url1! to file.) & goto :FAIL)
Or even (using parenthesised blocks):
(>> "!hostsfile!" echo !url1!) 2> nul && (
echo Successfully added !url1! to file.
) || (
echo Unable to write !url1! to file.
goto :FAIL
)
1) These two values are almost always are the same, but there are rare cases where they differ; the &&
and ||
operators do actually not care about ErrorLevel
, they rather use the exit code.
2) The trailing caret ^
lets cmd
ignore the next line-break and escape the following character, so two lines echo A^
and & echo B
cause the output A& echo B
as the &
appears escaped; to achieve two lines of output A
and B
, change the second line to SPACE + & echo B
, so the SPACE is escaped but the ampersand is not.
Upvotes: 6
Reputation: 24476
Firstly, if you want to redirect stderr to NUL, then just 2>NUL
. To choke off the stderr of echo
, you should encapsulate the echo
statements within an additional generation of parentheses, and redirect 2>NUL
for the entire code block.
And while you're adding parenthetical code blocks, to answer your "as an aside" question, you can pretty much put parentheses before or after any command. This is useful when writing compound command clauses / conditionals to stick with one command per line and make your code more readable.
Here's an illustration:
@echo off & setlocal
set "hosts=%systemroot%\system32\drivers\etc\hosts"
set "url=169.254.0.1 test"
2>NUL (
setlocal enabledelayedexpansion
>>"%hosts%" (echo !url!) && (
echo Successfully added.
endlocal
) || (
echo Addition failed. Try running this as administrator.
exit /b 1
)
)
exit /b
This successfully suppresses any "Access is denied." message, echoing only your specified success or fail message as appropriate.
By the way, I did (echo !url!)
to avoid echoing the trailing space, and just because I think it's prettier / easier to read than echo !url!&&
.
Upvotes: 1
Reputation:
I'd try something like this:
Set hostsfile=%Systemroot%\System32\drivers\etc\hosts
Findstr /I "!url1!" "!hostsfile!" 2>&1 >NUL &&(Echo !hostsfile! already contains !url1! & goto :whereever)
>> !hostsfile! ECHO !url1!
Findstr /I "!url1!" "!hostsfile!" 2>&1 >NUL ||(Echo Couldn't add !url1! to !hostsfile! & goto :whereever)
Upvotes: 0