I'm getting an error when I try to use ## in macro this is what I try to make:
With this defines:
#define PORT 2
#define PIN 3
I want that preprocessor generates:
PM2.3=1
when I call a macro like this:
SetPort(PORT,PIN)
Then, I see that I can make the substitution PORT and PIN at the same time that concatenation, then I think I must to use 2 defines:
#define SetP2(PORT,PIN) PM##PORT.PIN = 1
#define SetPort(PORT,PIN) SetP2(PORT,PIN)
but I get an error on:
#define PIN 3 --> expected identifier before numeric constant
and a warning on:
SetPort(PORT,PIN) --> Syntax error
Any idea?
This works for me:
$ cat portpin.c
#define PORT 2
#define PIN 3
#define SetP2(prefix,prt) prefix ## prt
#define SetPort(prt,pn) SetP2(PM,prt).pn = 1
SetPort(PORT,PIN)
$ gcc -E portpin.c
# 1 "portpin.c"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "portpin.c"
PM2. 3 = 1
$
I don't know how important it is for there to be no space between the . and the 3, but the preprocessor seems to want to insert it.
UPDATE:
Actually I tried your original code, and it seems to produce the same result, so my answer above is probably not much use to you.
UPDATE 2:
It turns out the OP is expecting the pre-processor to generate PM2.no3=1 and not PM2.3=1. This can easily be done as follows:
$ cat portpin.c
#define PORT 2
#define PIN 3
#define SetP2(PORT,PIN) PM##PORT.no##PIN=1
#define SetPort(PORT,PIN) SetP2(PORT,PIN)
SetPort(PORT,PIN)
$ gcc -E portpin.c
# 1 "portpin.c"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "portpin.c"
PM2.no3=1
$
Related
I have the following in test.c:
#if 1
foo boo bar
#endif
Then I run gcc like this:
gcc -E test.c -o test.pp
This is the test.pp output:
# 1 "test.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/include/stdc-predef.h" 1 3 4
# 1 "<command-line>" 2
# 1 "test.c"
foo boo bar
Is there a way to remove these # [something] directives and let only (in this case) foo boo bar only by using gcc flags? I mean, I would like that the preprocessor output would be only foo boo bar in this case.
I see the following output of gcc preprocessing. I don't find the documentation of the output format. Could anybody let me know what it is? Thanks.
$ cat a.h
#include "b.h"
$ cat b.h
#define X Y
$ gcc -E -dD - <<< '#include "a.h"'
...
# 1 "<command line>" 1
# 1 "<built-in>" 2
# 1 "<stdin>" 2
# 1 "./a.h" 1
# 1 "./b.h" 1
#define X Y
# 2 "./a.h" 2
# 2 "<stdin>" 2
When I try the following, I see more numbers, which are different from the above. I am not sure about what they mean either.
$ gcc -E -dD - <<< '#include <sys/socket.h>'
...
# 19 "/usr/include/x86_64-linux-gnu/asm/posix_types_64.h" 2 3 4
# 8 "/usr/include/x86_64-linux-gnu/asm/posix_types.h" 2 3 4
# 37 "/usr/include/linux/posix_types.h" 2 3 4
# 6 "/usr/include/asm-generic/socket.h" 2 3 4
# 1 "/usr/include/x86_64-linux-gnu/asm/sockios.h" 1 3 4
# 1 "/usr/include/asm-generic/sockios.h" 1 3 4
...
Unusual lines are linemarkers, which specify linenumber and filename. Numbers after the filename are special flags.
These are explained in GCC Preprocessor online documentation:
Source file name and line number information is conveyed by lines of
the form
# linenum filename flags
These are called linemarkers. They are inserted as needed into the
output (but never within a string or character constant). They mean
that the following line originated in file filename at line linenum.
filename will never contain any non-printing characters; they are
replaced with octal escape sequences.
After the file name comes zero or more flags, which are ‘1’, ‘2’, ‘3’,
or ‘4’. If there are multiple flags, spaces separate them. Here is
what the flags mean:
‘1’ This indicates the start of a new file.
‘2’ This indicates returning to a file (after having included another file).
‘3’ This indicates that the following text comes from a system header file, so certain warnings should be suppressed.
‘4’ This indicates that the following text should be treated as being wrapped in an implicit extern "C" block.
I have written the following random-number generator shell script:
for i in $(seq 1 $1) #for as many times, as the first argument ($1) defines...
do
echo "$i $((RANDOM%$2))" #print the current iteration number and a random number in [0, $2)
done
I run it like that:
./generator.sh 1000000000 101 > data.txt
to generate 1B rows of an id and a random number in [0,100] and store this data in file data.txt.
My desired output is:
1 39
2 95
3 61
4 27
5 85
6 44
7 49
8 75
9 52
10 66
...
It works fine for small number of rows, but with 1B, I get the following OOM error:
./generator.sh: xrealloc: ../bash/subst.c:5179: cannot allocate 18446744071562067968 bytes (4299137024 bytes allocated)
Which part of my program creates the error?
How could I write the data.txt file line-by-line?
I have tried replacing the echo line with:
echo "$i $((RANDOM%$2))" >> $3
where $3 is data.txt, but I see no difference.
The problem is your for loop:
for i in $(seq 1 $1)
This will first expand $(seq 1 $1), creating a very big list, which you then pass to for.
Using while, however, we can read the output of seq line-by-line, which will take a small amount of memory:
seq 1 1000000000 | while read i; do
echo $i
done
$(seq 1 $1) is computing the whole list before iterating over it. So it takes memory to store the entire list of 10^9 numbers, which is a lot.
I am not sure if you can make seq run lazily, i.e, get the next number only when needed. You can do a simple for loop instead:
for ((i=0; i<$1;++i))
do
echo "$i $((RANDOM%$2))"
done
If you want it fast this should work.
You will need to compile it using g++ using the form
g++ -o <executable> <C++file>
For example i did it this way
g++ -o inseq.exe CTest.cpp
CTest.cpp
#include <iostream>
#include <string>
#include <fstream>
#include <iomanip>
#include <cstdlib>
#include <sstream>
int main (int argc,char *argv[])
{
std::stringstream ss;
int x = atoi(argv[1]);
for(int i=1;i<=x;i++)
{
ss << i << "\n";
if(i%10000==0)
{
std::cout << ss.rdbuf();
ss.clear();
ss.str(std::string());
}
}
std::cout << ss.rdbuf();
ss.clear();
ss.str(std::string());
}
Speed comparisons
Lowest speeds of 3 tests for each of the methods presented for a 1000000 line file.
Jidder
$ time ./inseq 1000000 > file
real 0m0.143s
user 0m0.131s
sys 0m0.011s
Carpetsmoker
$ cat Carpet.sh
#!/bin/bash
seq 1 $1 | while read i; do
echo $i
done
.
$ time ./Carpet.sh 1000000 > file
real 0m12.223s
user 0m9.753s
sys 0m2.140s
Hari Shankar
$ cat Hari.sh
#!/bin/bash
for ((i=0; i<$1;++i))
do
echo "$i $((RANDOM%$2))"
done
.
$ time ./Hari.sh 1000000 > file
real 0m9.729s
user 0m8.084s
sys 0m1.064s
As you can see from the results, my way is slightly faster by about 60-70*.
Edit
Because python is great
$ cat Py.sh
#!/usr/bin/python
for x in xrange(1, 1000000):
print (x)
'
$ time ./Py.sh >file
real 0m0.543s
user 0m0.499s
sys 0m0.016s
4* slower than c++ so if the file was going to take an hour to make it would take 4 with these two lines.
EDIT 2
Decided to try Python and c++ on the 1000000000 line file
For a none CPU-intensive task this seems to be using a lottt of cpu
PID USER %CPU TIME+ COMMAND
56056 me 96 2:51.43 Py.sh
Results for Python
real 9m37.133s
user 8m53.550s
sys 0m8.348s
Results for c++
real 3m9.047s
user 2m53.400s
sys 0m2.842s
I want to perform the following exercise in linux. Impute2 is command line based software. I want to change its options automatically using for-loops but its throwing following error in ** bold ** .
The -int option is range stating from ** $int1 to $int2 ** for every ** $chunk **.
It means that here for chunk 34 the int will be from 165752599 to 170752599 (difference of 5000001) and the for chunk 35 the int will be 170752600 to 175752600 and so on till last chunk i.e. chunk 49 and its int will be 240752614 to 245752614.
for chunk in $(seq 34 49)
for int1 in $(seq 165752599 5000001 240752614)
for int2 in $(seq 170752599 5000001 245752614)
do ./impute2 -use_prephased_g -m map.txt -h hap.txt -l legend.txt \
-known_haps_g knownhap.txt -strand_g chr1_pos_strand_new \
-align_by_maf_g -int $int1 $int2 -Ne 20000 -iter 30 -burnin 10 \
-k 80 -k_hap 500 -os 0 1 2 3 -o result.out -o_gz -r result.summary \
-i resul.info
done
done
done
** bash: syntax error near unexpected token 'for' **
You have 3 fors and 3 dones but only one do. You need more do-do!
ie, for x in a; do for y in b; do for z ...
I came across a nice one-liner to search for text and print out the results with a given number of trailing and following lines. I'm trying to create a script out of this.
So far this is what I have:
# *********************************************************
# This uses nawk to list lines coming prior to and after
# the given search string.
# Format: xgrep <string> <file> <before> <after>
# ********************************************************
STR=$1
FILE=$2
BEF=$3
AFT=$4
export STR
export FILE
export BEF
export AFT
nawk 'c-->0;$0~s{if(b)for(c=b+1;c>1;c--)print r[(NR-c+1)%b];print;c=a}b{r[NR%b]=$0}' b=$BEF a=$AFT s=$STR $FILE
The problem is that the output of the nawk command doesn't appear on the screen
>xgrep "bin/sh" * 0 3
>
But if I type in the command, I get a proper output:
>nawk 'c-->0;$0~s{if(b)for(c=b+1;c>1;c--)print r[(NR-c+1)%b];print;c=a}b{r[NR%b]=$0}' b=0 a=3 s="bin/sh" *
#!/bin/sh
export AEGIS_PROJECT=$1
export EDITOR=cat
#!/bin/sh
aegis -cpu $pwd
aegis -dbu $1
#!/bin/sh
cd $HOME/ex_7/src/DTTCom
NRMan alphabuild clean
NRMan alphabuild library ex_7 8.19 app TEST DTTCom debug -j10
#!/bin/sh
cd $HOME/icx/src/DTTCom
NRMan alphabuild clean
NRMan alphabuild library icx_1 1.1 app TEST DTTCom debug -j10
#!/bin/sh
# *********************************************************
# This uses nawk to list lines coming prior to and after
# the given search string.
What's the reason for this and how can I get the script to work?
Try using:
xgrep "bin/sh" '*' 0 3
instead.
The expansion of the wildcard term is happening in the current shell before the arguments are passed to your script as shown in this transcript:
pax: xgrep include *.c 0 3
#include <stdio.h>
gawk: (FILENAME=binmath.c FNR=1) fatal: division by zero attempted in '%'
pax: xgrep include '*.c' 0 3
#include <stdio.h>
// Prototypes - should go in separate header file.
void compBinNum (char*);
#include <stdio.h>
#include <string.h>
#include <string.h>
#define UTF8ERR_TOOSHORT -1
#define UTF8ERR_BADSTART -2
#include <stdio.h>
#include <errno.h>
#include <errno.h>
int main (void) {
FILE *file = fopen ("words.txt", "r");
You can see how these arguments work with the following simple script and output:
pax: cat argtest
#!/bin/bash
echo Number of arguments: $#
echo Arguments: "$*"
pax: argtest *
Number of arguments: 32
Arguments: Makefile a.exe argtest binmath.c binmath.exe dev
file.db infile input.txt inputfile limit10 output.txt
p2.sh p2expected p2input1 p2input2 qq qq.c qq.cpp qq.exe
qq.exe.stackdump qq.pl qq.py qqin qqq.c qqq.s tmpfile
words2.txt xgrep xx.c xx.exe xx.pl
pax: argtest '*'
Number of arguments: 1
Arguments: *
Update:
Based on your question in the comments:
Thanks. It worked when I wrapped the file with single quotes. Is there a way that I could do this inside the script so that the user doesn't have to bother with typing single quotes?
No, that's because the shell is doing it before your script ever sees it. However, if you move the file specification to the end of the command line thus:
xgrep include 0 3 *.c
you could modify your script to not just process argument number 4 but every argument after that as well, one at a time. Then, when they've been expanded by the shell, it won't matter.
Something like (with the gawk/nawk on a single line):
STR=$1
BEF=$2
AFT=$3
while [[ ! -z "$4" ]] ; do
echo ========== "$4"
gawk 'c-->0;$0~s{if(b)for(c=b+1;c>1;c--)
print r[(NR-c+1)%b];print;c=a}b{r[NR%b]=$0}'
b=$BEF a=$AFT s=$STR "$4"
| sed "s/^/$4: /"
shift
done
echo ==========
Letting the shell handle your expansion and using a loop also allows you to do tricks such as printing the file name with each block (or line) of output:
pax: xgrep include 0 3 *.c
========== binmath.c
binmath.c: #include <stdio.h>
binmath.c:
binmath.c: // Prototypes - should go in separate header file.
binmath.c: void compBinNum (char*);
========== qq.c
qq.c: #include <stdio.h>
qq.c: #include <string.h>
qq.c: #include <string.h>
qq.c:
qq.c: #define UTF8ERR_TOOSHORT -1
qq.c: #define UTF8ERR_BADSTART -2
========== qqq.c
========== xx.c
xx.c: #include <stdio.h>
xx.c: #include <errno.h>
xx.c: #include <errno.h>
xx.c:
xx.c: int main (void) {
xx.c: FILE *file = fopen ("words.txt", "r");
==========