dcl executing program using foreign command - openvms

How would you go about doing this?
I have a file which contains roughly 40 lines, each line are variables for an .exe file.
I've setup a foreign command
$ CC := "$something$something:file.exe"
I then try to loop through the file line by line
{Method1}
$ OPEN a file.txt
$ loop:
$ READ/END_OF_FILE:end a b
$ CC b
$ goto loop
$ end:
My problem is because the value of b contains quotes (" ") around it the file.exe does not execute
I also tried to put CC on the start of each line of file.txt (shown below) and run each line 1 at a time just like above but it gives an error that it cannot run CC.exe from the default location. As you can see below variables 2-4 need to be in double quotes if that matters for method 1 ideas.
{Method 2}
$ CC variable1 "variable2" "variable3" "variable4"
What I need to do in the end is run about 10 of these at one time, so i think if I could get method 2 to work that would be the best.

I'm not sure whether I fully understand what you are trying to achieve. From what I read, I would for a text file (file.txt) like
This
That
"Quoted"
"Quoted blank"
" "
This and that
"This and" "that"
write a command procedure (echo.com) like
$ cc:=$sys$disk:[]echo
$ OPEN a file.txt
$ loop:
$ READ/END_OF_FILE:end a b
$ show symb b
$ CC 'b'
$ goto loop
$ end:
$ CLOSE a
which when run gives:
$ #echo
B = "This"
arg1: 'this'
B = "That"
arg1: 'that'
B = ""Quoted""
arg1: 'Quoted'
B = ""Quoted blank""
arg1: 'Quoted blank'
B = "" ""
arg1: ' '
B = "This and that"
arg1: 'this'
arg2: 'and'
arg3: 'that'
B = ""This and" "that""
arg1: 'This and'
arg2: 'that'
$
where echo.exe is just an simple C program to print argv, starting with argument 1 and quoted with single quotes; and the $ show symb b is just to show what was actually read from the file; the symbols content is quoted with double quotes.
This is more or less what you had, except the $ CC 'b' where the single quotes tells dcl to expand the symbol b. And a close of the input file after reading it is not a bad idea.
No, there is no need to DEFINE anything. For the foreign command you don't have to have the .exe, it's the default.

I was able to get it working by defining CC then using Method 2 in order to call each line
DEFINE CC $something$something:file.exe;

Related

Delete everything before and after a string using sed

I have data in a file in below form :--
The symbol ":=" was substituted for "QUERY" to continue.
SQL> _id : MS
itm : 4
it : NO
------
PL/SQL procedure successfully completed.
I want to delete everything before _id and after ------ .
To delete everything before _id I used following sed
sed '/_id/,$!d' 1.txt
It deletes the row before _id but doesnt delete SQL> .
Similarly I used below sed to delete all everything after ------ but it doesnt delete the rows below it
sed 's/\------.*/------/' 1.txt
Can someone help me where I am doing wrong ? What I need is :--
_id : MS
itm : 4
it : NO
Using sed
Try:
$ sed -n '/_id/,/------/{ s/.*_id/_id/; /------/q; p}' 1.txt
_id : MS
itm : 4
it : NO
How it works:
-n
This tells sed not to print unless we explicitly ask it to.
/_id/,/------/{...}
This selects a range of lines that start with a line containing _id and end with a line containing ------. For those lines the commands in curly braces are executed.
s/.*_id/_id/
On the line that contains _id, this removes everything before _id.
/------/q
On the line that contains ------, this tells sed to quit.
p
For lines that reach this command, this tells sed to print the line.
Using awk
$ awk -v RS='------' '/_id/{sub(/.*_id/, "_id"); print}' ORS="" 1.txt
_id : MS
itm : 4
it : NO
How it works:
-v RS='------'
This set ------ as the record separator.
/_id/{sub(/.*_id/, "_id"); print}
For any records that contain _id, we remove everything before _id and print the current record.
ORS=""
This sets the output record separator to the empty string.

How to join next line if certain character is there in AWK?

In a text file (windows) i have:
sometexthere"
nothingtodohere
yessomethinghere"
etc
Using AWK (in Ubuntu) how to delete the apostrophe " at the end of the line, replace it with a semi colon : and join the next line?
so it looks like this:
sometexthere:nothingtodohere
yessomethinghere:etc
This way:
awk '1' RS='"\n' ORS=':' yourfile
Just set your record sep. to double quotes plus break line, and your output record sep. to the join character.
For DOS line breaks just adjust the regex:
awk '1' RS='"\r\n' ORS=':' yourfile
Note: what that 1 means?
Short answer, It's just a shortcut to avoid using the print statement. In awk when a condition gets matched the default action is to print the input line, example:
$ echo "test" |awk '1'
test
That's because 1 will be always true, so this expression is equivalent to:
$ echo "test"|awk '1==1'
test
$ echo "test"|awk '{if (1==1){print}}'
test

awk: how to delete first and last value on entire column

I have a data that is comprised of several columns. On one column I would like to delete two commas that are each located in beginning and the end of entire column. My data looks something like this:
a ,3,4,3,2,
b ,3,4,5,1,
c ,1,5,2,4,5,
d ,3,6,24,62,3,54,
Can someone teach me how to delete the first and last commas on this data? I would appreciate it.
$ awk '{gsub(/^,|,$/,"",$NF)}1' file
a 3,4,3,2
b 3,4,5,1
c 1,5,2,4,5
d 3,6,24,62,3,54
awk '{sub(/,/,"",$0); print substr($0,0,length($0)-1)}' input.txt
Output:
a 3,4,3,2,
b 3,4,5,1,
c 1,5,2,4,5,
d 3,6,24,62,3,54
You can do it with sed too:
sed -e 's/,//' -e 's/,$//' file
That says "substitue the first comma on the line with nothing" and then "substitute a comma followed by end of line with nothing".
If you want it to write a new file, do this:
sed -e 's/,//' -e 's/,$//' file > newfile.txt

In AWK, is it possible to specify "ranges" of fields?

In AWK, is it possible to specify "ranges" of fields?
Example. Given a tab-separated file "foo" with 100 fields per line, I want to print only the fields 32 to 57 for each line, and save the result in a file "bar". What I do now:
awk 'BEGIN{OFS="\t"}{print $32, $33, $34, $35, $36, $37, $38, $39, $40, $41, $42, $43, $44, $45, $46, $47, $48, $49, $50, $51, $52, $53, $54, $55, $56, $57}' foo > bar
The problem with this is that it is tedious to type and prone to errors.
Is there some syntactic form which allows me to say the same in a more concise and less error prone fashion (like "$32..$57") ?
Besides the awk answer by #Jerry, there are other alternatives:
Using cut (assumes tab delimiter by default):
cut -f32-58 foo >bar
Using perl:
perl -nle '#a=split;print join "\t", #a[31..57]' foo >bar
Mildly revised version:
BEGIN { s = 32; e = 57; }
{ for (i=s; i<=e; i++) printf("%s%s", $(i), i<e ? OFS : "\n"); }
You can do it in awk by using RE intervals. For example, to print fields 3-6 of the records in this file:
$ cat file
1 2 3 4 5 6 7 8 9
a b c d e f g h i
would be:
$ gawk 'BEGIN{f="([^ ]+ )"} {print gensub("("f"{2})("f"{4}).*","\\3","")}' file
3 4 5 6
c d e f
I'm creating an RE segment f to represent every field plus it's succeeding field separator (for convenience), then I'm using that in the gensub to delete 2 of those (i.e the first 2 fields), remember the next 4 for reference later using \3, and then delete what comes after them. For your tab-separated file where you want to print fields 32-57 (i.e. the 26 fields after the first 31) you'd use:
gawk 'BEGIN{f="([^\t]+\t)"} {print gensub("("f"{31})("f"{26}).*","\\3","")}' file
The above uses GNU awk for it's gensub() function. With other awks you'd use sub() or match() and substr().
EDIT: Here's how to write a function to do the job:
gawk '
function subflds(s,e, f) {
f="([^" FS "]+" FS ")"
return gensub( "(" f "{" s-1 "})(" f "{" e-s+1 "}).*","\\3","")
}
{ print subflds(3,6) }
' file
3 4 5 6
c d e f
Just set FS as appropriate. Note that this will need a tweak for the default FS if your input file can start with spaces and/or have multiple spaces between fields and will only work if your FS is a single character.
I'm late but this is quick at to the point so I'll leave it here. In cases like this I normally just remove the fields I don't need with gsub and print. Quick and dirty example, since you know your file is delimited by tabs you can remove the first 31 fields:
awk '{gsub(/^(\w\t){31}/,"");print}'
example of removing 4 fields because lazy:
printf "a\tb\tc\td\te\tf\n" | awk '{gsub(/^(\w\t){4}/,"");print}'
Output:
e f
This is shorter to write, easier to remember and uses less CPU cycles than horrendous loops.
You can use a combination of loops and printf for that in awk:
#!/bin/bash
start_field=32
end_field=58
awk -v start=$start_field -v end=$end_field 'BEGIN{OFS="\t"}
{for (i=start; i<=end; i++) {
printf "%s" $i;
if (i < end) {
printf "%s", OFS;
} else {
printf "\n";
}
}}'
This looks a bit hacky, however:
it properly delimits your output based on the specified OFS, and
it makes sure to print a new line at the end for each input line in the file.
I do not know a way to do field range selection in awk. I know how to drop fields at the end of the input (see bellow), but not easily at the beginning. Bellow, the hard way to drop fields at the beginning.
If you know a character c that is not included in your input, you could use the following awk script:
BEGIN { s = 32; e = 57; c = "#"; }
{ NF = e # Drop the fields after e.
$s = c $s # Put a c in front of the s field.
sub(".*"c, "") # Drop the chars before c.
print # Print the edited line.
}
EDIT:
And I just thought that you can always find a character that is not in the input: use \n.
Unofrtunately don't seem to have access to my account anymore, but also don't have 50 rep to add a comment anyway.
Bob's answer can be simplified a lot using 'seq':
echo $(seq -s ,\$ 5 9| cut -d, -f2-)
$6,$7,$8,$9
The minor disadvantage is you have to specify your first field number as one lower.
So to get fields 3 through 7, I specify 2 as the first argument.
seq -s ,\$ 2 7 sets field seperator for seq at ',$' and yields 2,$3,$4,$5,$6,$7
cut -d, -f2- sets field delimiter at ',' and basically cuts of everything before the first comma, by showing everything from the second field on. Thus resulting in $3,$4,$5,$6,$7
When combined with Bob's answer, we get:
$ cat awk.txt
1 2 3 4 5 6 7 8 9
a b c d e f g h i
$ awk "{print $(seq -s ,\$ 2 7| cut -d, -f2-)}" awk.txt
3 4 5 6 7
c d e f g
$
I use this simple function, which does not check that the field range exists in the line.
function subby(f,l, s) {
s = $f
for(i=f+1;i<=l;i++)
s = sprintf("%s %s",s,$i)
return s
}
(I know OP requested "in AWK" but ... )
Using bash expansion on the command line to generate arguments list;
$ cat awk.txt
1 2 3 4 5 6 7 8 9
a b c d e f g h i
$ awk "{print $(c="" ;for i in {3..7}; do c=$c\$$i, ; done ; c=${c%%,} ; echo $c ;)}" awk.txt
3 4 5 6 7
c d e f g
explanation ;
c="" # var to hold args list
for i in {3..7} # the required variable range 3 - 7
do
# replace c's value with concatenation of existing value, literal $, i value and a comma
c=$c\$$i,
done
c=${c%%,} # remove trailing/final comma
echo $c #return the list string
placed on single line using semi-colons, inside $() to evaluate/expand in place.

AWK - explanation for example

I have a file 1:
1
2
3
This command prints:
$ awk 'BEGIN{system("cat " 1)}'
1
2
3
.
$ awk 'BEGIN{system( "cat '\''" 1 "'\''") }'
1
2
3
I changed the filename from "1" to "one"
I have a file one:
1
2
3
Now, the command does not work:
$ awk 'BEGIN{system("cat " one)}'
|
.
$ awk 'BEGIN{system( "cat '\''" one "'\''") }'
cat: : No such file or directory
Why now commands do not work?
Thank you for the explanation.
In your examples, awk interprets 1 as a literal 1 and one as a variable which has no value. That means system is trying to execute cat {empty} or cat ''.
Try this:
awk 'BEGIN{one = "one" ; system("cat " one)}'
or:
awk 'BEGIN{system("cat one")}'
if your file name is a number, you could write the number in system() directly, awk will convert it into string value internally. you even could write expression to get the number as result. for example:
system("cat "4-3) should work for your "1" case as well. to see the difference, you could name a file as "1+1" then system("cat "1+1) won't work, it will complain that file "2" doesn't exist.
for the "one" example: the 'one' in your system() worked not like string "one" but a variable named "one". in awk, if a variable was not assigned, its default value is empty string.
In awk, 1 has the value of 1 and the variable named one is an empty string. So "cat" 1 is the string cat 1, but "cat" one is the string cat. The string "cat '\''" one "'\''" is the string cat '', so you are passing the empty string as the first argument to cat.