i want to do this in one command:
set myvar="hello" && echo %myvar%
and get "hello" on the screen.
but i get %myvar% instead. How can this expansion be done immediately so i get "hello"?
Edit:
how does it look like when using angle brackets:
set "var=<hello>"& echo %^var%
Option 1 - use CALL to get an extra round of expansion
The CALL command introduces an extra round of expansion. But you don't want the variable to be expanded before the CALL is executed, otherwise you will get the value that existed before the line was executed (assuming it already existed). So you need a way to delay the expansion.
Within a batch script, you would use call echo %%myvar%%, but doubling percents does not work on the command line.
The trick to get it to work on the command line is to introduce a dissappearing caret into the name. The normal expansion interprets the caret as part of the name, so the variable is not found, and nothing is expanded. The caret is consumed before the CALL expansion, so the correct result is then obtained.
set "myvar=hello"&call echo %^myvar%
Note that this will not work in the unlikely event that variable named ^myvar actually exists.
Option 2 - persistently enable delayed expansion
cmd /v:on
set "myvar=hello"&echo !myvar!
Option 3 - temporarily enable delayed expansion
set "myvar=hello"&cmd /v:on /c echo !myvar!
Update for edited question
If your variable contains poison characters like < or >, then your best choice is to use Option 2 or 3 because delayed expansion is immune to poison characters.
The obvious way you could use option 1 is if you escape the poison characters during the definition.
set "myvar=^<hello^>"&call echo %^myvar%
Not a very practical solution.
I suppose you could do the following to avoid delayed expansion and avoid modifying the content:
set "myvar=<hello>"&for /f "delims=" %A in ('echo ^"%^myvar%^"') do #echo %~A
But this can have problems if your variable content might have embedded quotes.
Assuming you want to do this at the command line as opposed to in a batch:
set myvar="hello" && call echo %myvar%
Related
-- Edit : Resolved. See answer.
Background:
I'm writing a shell that will perform some extra actions required on our system when someone resizes a database.
The shell is written in ksh (requirement), the OS is Solaris 5.10 .
The problem is with one of the checks, which verifies there's enough free space on the underlying OS.
Problem:
The check reads the df -k line for root, which is what I check in this step, and prints it to a file. I then "read" the contents into variables which I use in calculations.
Unfortunately, when I try to run an arithmetic operation on one of the variables, I get an error indicating it is null. And a debug output line I've placed after that line verifies that it is null... It lost it's value...
I've tried every method of doing this I could find online, they work when I run it manually, but not inside the shell file.
(* The file does have #!/usr/bin/ksh)
Code:
df -k | grep "rpool/ROOT" > dftest.out
RPOOL_NAME=""; declare -i TOTAL_SIZE=0; USED_SPACE=0; AVAILABLE_SPACE=0; AVAILABLE_PERCENT=0; RSIGN=""
read RPOOL_NAME TOTAL_SIZE USED_SPACE AVAILABLE_SPACE AVAILABLE_PERCENT RSIGN < dftest.out
\rm dftest.out
echo $RPOOL_NAME $TOTAL_SIZE $USED_SPACE $AVAILABLE_SPACE $AVAILABLE_PERCENT $RSIGN
((TOTAL_SIZE=$TOTAL_SIZE/1024))
This is the result:
DBResize.sh[11]: TOTAL_SIZE=/1024: syntax error
I'm pulling hairs at this point, any help would be appreciated.
The code you posted cannot produce the output you posted. Most obviously, the error is signalled at line 11 but you posted fewer than 11 lines of code. The previous lines may matter. Always post complete code when you ask for help.
More concretely, the declare command doesn't exist in ksh, it's a bash thing. You can achieve the same result with typeset (declare is a bash equivalent to typeset, but not all options are the same). Either you're executing this script with bash, or there's another error message about declare, or you've defined some additional commands including declare which may change the behavior of this code.
None of this should have an impact on the particular problem that you're posting about, however. The variables created by read remain assigned until the end of the subshell, i.e. until the code hits a ), the end of a pipe (left-hand side of the pipe only in ksh), etc.
About the use of declare or typeset, note that you're only declaring TOTAL_SIZE as an integer. For the other variables, you're just assigning a value which happens to consist exclusively of digits. It doesn't matter for the code you posted, but it's probably not what you meant.
One thing that may be happening is that grep matches nothing, and therefore read reads an empty line. You should check for errors. Use set -e in scripts to exit at the first error. (There are cases where set -e doesn't catch errors, but it's a good start.)
Another thing that may be happening is that df is splitting its output onto multiple lines because the first column containing the filesystem name is too large. To prevent this splitting, pass the option -P.
Using a temporary file is fragile: the code may be executed in a read-only directory, another process may want to access the same file at the same time... Here a temporary file is useless. Just pipe directly into read. In ksh (unlike most other sh variants including bash), the right-hand side of a pipe runs in the main shell, so assignments to variables in the right-hand side of a pipe remain available in the following commands.
It doesn't matter in this particular script, but you can use a variable without $ in an arithmetic expression. Using $ substitutes a string which can have confusing results, e.g. a='1+2'; $((a*3)) expands to 7. Not using $ uses the numerical value (in ksh, a='1+2'; $((a*3)) expands to 9; in some sh implementations you get an error because a's value is not numeric).
#!/usr/bin/ksh
set -e
typeset -i TOTAL_SIZE=0 USED_SPACE=0 AVAILABLE_SPACE=0 AVAILABLE_PERCENT=0
df -Pk | grep "rpool/ROOT" | read RPOOL_NAME TOTAL_SIZE USED_SPACE AVAILABLE_SPACE AVAILABLE_PERCENT RSIGN
echo $RPOOL_NAME $TOTAL_SIZE $USED_SPACE $AVAILABLE_SPACE $AVAILABLE_PERCENT $RSIGN
((TOTAL_SIZE=TOTAL_SIZE/1024))
Strange...when I get rid of your "declare" line, your original code seems to work perfectly well (at least with ksh on Linux)
The code :
#!/bin/ksh
df -k | grep "/home" > dftest.out
read RPOOL_NAME TOTAL_SIZE USED_SPACE AVAILABLE_SPACE AVAILABLE_PERCENT RSIGN < dftest.out
\rm dftest.out
echo $RPOOL_NAME $TOTAL_SIZE $USED_SPACE $AVAILABLE_SPACE $AVAILABLE_PERCENT $RSIGN
((TOTAL_SIZE=$TOTAL_SIZE/1024))
print $TOTAL_SIZE
The result :
32962416 5732492 25552588 19% /home
5598
Which are the value a simple df -k is returning. The variables seem to last.
For those interested, I have figured out that it is not possible to use "read" the way I was using it.
The variable values assigned by "read" simply "do not last".
To remedy this, I have applied the less than ideal solution of using the standard "while read" format, and inside the loop, echo selected variables into a variable file.
Once said file was created, I just "loaded" it.
(pseudo code:)
LOOP START
echo "VAR_A="$VAR_A"; VAR_B="$VAR_B";" > somefile.out
LOOP END
. somefile.out
I have multiple results (Radiology, Labs, Pathology, Transcriptions) for the same patient in a file and I am only interested in getting results for a set of particular values. For example: I want to look for a radiology report on the first line and patient MRN 123456789 on the second line.
Can this be achieved using findstr? Thanks
MSH|^~\&|RADIOLOGY|1|SCM||20150303||ORU|20150303|T|2.3|20150303
PID||1111111|123456789^^^MRN_SB^||TEST^PATIENT^^^||19000101||^^||
PV1|1|E|ER^ER^1^SB||||||||||||||||||||||||||||||||||||||||||||||
ORC|RE|36543654|36543654|3003487889
#ECHO OFF
SETLOCAL
:: remove variables starting $
FOR /F "delims==" %%a In ('set $ 2^>Nul') DO SET "%%a="
SET "found="
SET "mrn=%1"
FOR /f "delims=" %%o IN (q29931949.txt) DO (
FOR /f "tokens=1-4delims=|" %%a IN ("%%o") DO (
IF DEFINED found IF "%%a"=="PID" (
SET "$2=%%o"
CALL :report "%%b" "%%c" "%%d"
)
SET "found="
IF "%%a"=="MSH" IF "%%b"=="RADIOLOGY" SET found=Y
IF "%%a"=="MSH" IF "%%c"=="RADIOLOGY" SET found=Y
IF DEFINED found SET "$1=%%o"
)
)
GOTO :EOF
:report
SET "field=%~1"
IF NOT DEFINED field GOTO :EOF
FOR /f "tokens=1delims=^^" %%r IN ("%~1") DO SET "field=%%r"
IF "%field%"=="%mrn%" FOR /F "tokens=1*delims==" %%r In ('set $') DO ECHO(%%s
shift
GOTO report
I used a file named q29931949.txt containing your data for my testing.
You don't really supply enough information to produce a result. For instance, is "MRN" a required data item?
This procedure will find two consecutive lines, the first one having "MSH" in he first column and "RADIOLOGY" in the second or third and the second line having "PID" in the first column snd either the second, third or fourth column containing the target number.
You'd run the routine using thisbatchaname 123456789
It accepts the parameter 123456789 and assigns that to mrn.
It then reads the file and assigns each line in tun to %%o, and tokenises the line on |, applying tokens 1-4 to %%a..%%d rspectively.
The main loop sets found to empty and then to Y only if the first field is MSH and the second or thid RADIOLOGY. If the found flag is set, the original line in %%o is applied to $1. Only if found is set at the start of the loop (which means that the previous line is MSH/RADIOLOGY) will the routine :report be called after $2 has the original contents of the second line assigned.
The :report routine sets field to the first parameter to see whether there are remaining parameters to process. The for then assigns the part of the field up to the first caret (^) to field. If this matches the mrn input from the command line, then the $ variables are echoed to the console (you don't say what you actually want to do with the data). Regardless, the remaining parameters are checked.
The reson for checking the second/third(/fourth) parameter is to cater for the presence or absence of data in the fields as consecutive | characters are interpreted as a single delimiter.
Find a HL7 parser library for Your programming/scripting language of choice and use it. It is not worth it to write a HL7 parser from scratch. There should be libraries available for all popular languages that You can use.
If You then have specific questions, feel free to ask again.
I've been searching all over the place and since I'm taking my first steps in PERL this might be one of he dumbest questions but here it goes.
So I'm creating a script to manage my windows and later bind it to keyboard shortcuts, so I I'm trying to run a command and passing some variables:
my $command = `wmctrl -r :ACTIVE: -e 0,0,0,$monitors->{1}->{'width'}/2,$monitors->{1}->{'height'}`;
But I get an error saying I'm not passing the right parameters to the command, but if I do this, everything works great:
my $test = $monitors->{1}->{'width'}/2;
my $command = `wmctrl -r :ACTIVE: -e 0,0,0,$test,$monitors->{1}->{'height'}`;
So do I really have to do this? assign it first to a variable and then pass it, or there's a more elegant way of doing it?
The backticks operator (or the qx{}) accepts A string which is (possibly) interpolated. So accepts string and not expression like $var/2.
Thats mean than the $variables ($var->{1}->{some} too) are expanded but not the arithmetic expressions.
Therefore your 2 step variant works, but not the first.
If you want evaluate an expression inside the string you can use the next:
my $ans=42;
print "The #{[ $ans/2 ]} is only the half of answer\n";
prints
The 21 is only the half of answer
but it is not very readable, so better and elegant is what you're already doing - calculate the command argument in andvace, and to the qx{} or backticks only pass the calculated $variables.
I'm writing some PowerShell scripts to work with our source control software (which is not a PowerShell cmdlet) and I'm running into a problem using variables as command line arguments when they are preceded by an =, like this:
cm mklabel lb:BL$baseline -c=$comment
This ends up create a label in with the comment of "$comment". If I put a space after the =, it looks like it evaluates the variable properly, but the command does not associate the comment with -c argument anymore. Is there a way to force the variable to be evaluated despite the =?
Try:
cm mklabel lb:BL$baseline -c=($comment)
Try
cm mklabel lb:BL$baseline "-c=$comment"
I'm trying to create 2 user environment variables with the following defintion:
datel=%date:~-4%%date:~3,2%%date:~0,2%
datetime=%date:~-4%%date:~3,2%%date:~0,2%-%time:~0,2%_%time:~3,2%_%time:~6,2%
so that every time I call:
echo %datel%
echo %datetime%
I get:
20110407
20110407-11_45_45
I can define the user environment variables without problems in the GUI (Computer->(Right Click)Properties->Advanced System Settings->Environment Variables) and when I do a "set" in a new cmd window I get the following:
>set da
datel=%date:~-4%%date:~3,2%%date:~0,2%
datetime=%date:~-4%%date:~3,2%%date:~0,2%-%time:~0,2%_%time:~3,2%_%time:~6,2%
But then "echoing" them is not what I expected:
C:\Users\jaravj
>echo %datel%
%date:~-4%%date:~3,2%%date:~0,2%
C:\Users\jaravj
>echo %datetime%
%date:~-4%%date:~3,2%%date:~0,2%-%time:~0,2%_%time:~3,2%_%time:~6,2%
Thanks a huge lot in advance.
Use call echo %datel% which results in another parsing pass (which you need here). echo by itself will not expand any environment variables, that does the shell upon parsing a line. Therefore you need to force that.
That's undocumented, however, so take that with a grain of salt. A more robust (i.e. actually supported) option might be to use a subroutine:
:expand
echo.%*
goto :eof
and then call it with
call :expand echo %datel%
Or use the delayed expansion, then you are able to expands two times in one line.
setlocal
set "datel=!date:~-4!!date:~3,2!!date:~0,2!"
setlocal EnableDelayedExpansion
echo %datel%
It's works because, first the batch line parser expands %datel% to !date:~-4!!date:~3,2!!date:~0,2! and after all percent expansions are done.
Then the escape characters are handled, and then as the last phase the parser expands the exclamations are expanded.
Explained in how cmd.exe parse scripts