I intend to automate compile and run process in C++, I wrote the following code as compile-run.sh
#! /bin/bash
clang++ $1.cpp -o $1.out && ./$1.out
I put this compile-run.sh in /usr/local/bin for global usage,
and when I type the command compile-run.sh XXX.cpp, it intend to compile and run the specified cpp file. But the problem now is I have to manually removed ".cpp" in the command.
Is there any way to trim the last X number of character and assign to a variable in general?
Is there any way to trim the .cpp and apply trimmed $1 in the code?
Is there better way to automate compile and run process?
well, an ugly way could be by using something like:
#! /bin/bash
filename=$1
temp="${filename%%.cpp}"
clang++ $temp.cpp -o $temp.out && ./$temp.out
another way, if you want to trim the last 4 characters whatever the last part is:
#! /bin/bash
filename=$1
temp="${filename::-4}"
clang++ $temp.cpp -o $temp.out && ./$temp.out
but for substrings you could also use cut: ie. https://stackabuse.com/substrings-in-bash/
Related
I want to use ncap2 to make a large number of variables a function of time in a netcdf file. I therefore wanted to build up the command argument in a loop and store in a bash variable command and then apply it as a variable, which I often do with cdo like this
cdo $command in.nc out.nc
I build up my command like this:
varlist="hfls hfss prlr prw rlds rlus rlut rsds rsdt rsus rsut clt evspsbl"
command=""
for var in $varlist ; do
command+=" -s '${var}[time,lat,lon]=${var}'"
done
echo $command
when I then attempt to do this :
ncap2 $command in.nc out.nc
I get a segmentation fault and core dump. But if I cut and paste the result of the echo command into the ncap2 statement,
ncap2 -s 'hfls[time,lat,lon]=hfls' -s 'hfss[time,lat,lon]=hfss' -s 'prlr[time,lat,lon]=prlr' -s 'prw[time,lat,lon]=prw' -s 'rlds[time,lat,lon]=rlds' -s 'rlus[time,lat,lon]=rlus' -s 'rlut[time,lat,lon]=rlut' -s 'rsds[time,lat,lon]=rsds' -s 'rsdt[time,lat,lon]=rsdt' -s 'rsus[time,lat,lon]=rsus' -s 'rsut[time,lat,lon]=rsut' -s 'clt[time,lat,lon]=clt' -s 'evspsbl[time,lat,lon]=evspsbl' $dir/$file /scratch/b/$USER/${file%???}_corrected.nc
It works fine... I'm sure it is something to do with the way I'm handling the strings, but my experiments trying to change around quotes etc, didn't seem to work.
Yes, it seems to be a shell-quoting issue.
Rather than try to create a simpler analogue for testing, let me start by just asking, does it work if you use this instead?
eval ncap2 $command in.nc out.nc
I often find Bash syntax very helpful, e.g. process substitution like in diff <(sort file1) <(sort file2).
Is it possible to use such Bash commands in a Makefile? I'm thinking of something like this:
file-differences:
diff <(sort file1) <(sort file2) > $#
In my GNU Make 3.80 this will give an error since it uses the shell instead of bash to execute the commands.
From the GNU Make documentation,
5.3.2 Choosing the Shell
------------------------
The program used as the shell is taken from the variable `SHELL'. If
this variable is not set in your makefile, the program `/bin/sh' is
used as the shell.
So put SHELL := /bin/bash at the top of your makefile, and you should be good to go.
BTW: You can also do this for one target, at least for GNU Make. Each target can have its own variable assignments, like this:
all: a b
a:
#echo "a is $$0"
b: SHELL:=/bin/bash # HERE: this is setting the shell for b only
b:
#echo "b is $$0"
That'll print:
a is /bin/sh
b is /bin/bash
See "Target-specific Variable Values" in the documentation for more details. That line can go anywhere in the Makefile, it doesn't have to be immediately before the target.
You can call bash directly, use the -c flag:
bash -c "diff <(sort file1) <(sort file2) > $#"
Of course, you may not be able to redirect to the variable $#, but when I tried to do this, I got -bash: $#: ambiguous redirect as an error message, so you may want to look into that before you get too into this (though I'm using bash 3.2.something, so maybe yours works differently).
One way that also works is putting it this way in the first line of the your target:
your-target: $(eval SHELL:=/bin/bash)
#echo "here shell is $$0"
If portability is important you may not want to depend on a specific shell in your Makefile. Not all environments have bash available.
You can call bash directly within your Makefile instead of using the default shell:
bash -c "ls -al"
instead of:
ls -al
There is a way to do this without explicitly setting your SHELL variable to point to bash. This can be useful if you have many makefiles since SHELL isn't inherited by subsequent makefiles or taken from the environment. You also need to be sure that anyone who compiles your code configures their system this way.
If you run sudo dpkg-reconfigure dash and answer 'no' to the prompt, your system will not use dash as the default shell. It will then point to bash (at least in Ubuntu). Note that using dash as your system shell is a bit more efficient though.
It's not a direct answer to the question, makeit is limited Makefile replacement with bash syntax and it can be useful in some cases (I'm the author)
rules can be defined as bash-functions
auto-completion feature
Basic idea is to have while loop in the end of the script:
while [ $# != 0 ]; do
if [ "$(type -t $1)" == 'function' ]; then
$1
else
exit 1
fi
shift
done
https://asciinema.org/a/435159
I want to apply some gvim regular expression to a file in command line. I understand that we have to use command gvim -c '<regexp>' $filename. But I open the file visually that user can see, is there any way to implement in the background, I mean without opening the file visually?
regards
keerthan
Alternatives
Unless you really need special Vim capabilities, you're probably better off using non-interactive tools like sed, awk, or Perl / Python / Ruby / your favorite scripting language here.
That said, you can use Vim (the terminal version, not GUI-only GVIM) non-interactively:
Silent Batch Mode
For very simple text processing (i.e. using Vim like an enhanced 'sed' or 'awk', maybe just benefitting from the enhanced regular expressions in a :substitute command), use Ex-mode.
REM Windows
call vim -N -u NONE -n -i NONE -es -S "commands.ex" "filespec"
Note: silent batch mode (:help -s-ex) messes up the Windows console, so you may have to do a cls to clean up after the Vim run.
# Unix
vim -T dumb --noplugin -n -i NONE -es -S "commands.ex" "filespec"
Attention: Vim will hang waiting for input if the "commands.ex" file doesn't exist; better check beforehand for its existence! Alternatively, Vim can read the commands from stdin. You can also fill a new buffer with text read from stdin, and read commands from stderr if you use the - argument.
Full Automation
For more advanced processing involving multiple windows, and real automation of Vim (where you might interact with the user or leave Vim running to let the user take over), use:
vim -N -u NONE -n -c "set nomore" -S "commands.vim" "filespec"
Here's a summary of the used arguments:
-T dumb Avoids errors in case the terminal detection goes wrong.
-N -u NONE Do not load vimrc and plugins, alternatively:
--noplugin Do not load plugins.
-n No swapfile.
-i NONE Ignore the |viminfo| file (to avoid disturbing the
user's settings).
-es Ex mode + silent batch mode -s-ex
Attention: Must be given in that order!
-S ... Source script.
-c 'set nomore' Suppress the more-prompt when the screen is filled
with messages or output to avoid blocking.
To modify the file using a regular expression, write it and quit immediately, you could use something like vim -c <command> -c x <file>. From a technical point of view, it is possible to suppress output by redirecting the standard streams and run this in the background – if that is what you want.
I need to execute this command in my c++ code:
mkdir -p sample_directory/{1..10}
to make 10 directory . But when I use it in system function in my code:
system("mkdir -p sample_director/{1..10}");
after execution this make just one directory by this name :{1..10}
how can i fix it?
Brace expansion is not in POSIX, so not all shells implement it. In particular, in POSIX, system is supposed to invoke sh, which is supposed to act like a "plain" POSIX shell rather than bash or some other feature-rich shell. So it won't do the brace expansion.
You could directly invoke bash if you want bash to process the command...
system("bash -c 'mkdir -p sample_director/{1..10}'");
or you could just make 10 separate system calls. Or other workarounds, I'm sure you can think of some.
You can probably try to do the same using a loop construct.
# include <cstdlib>
# include <string>
using namespace std;
int main(){
for(int i=1;i<=10;i++){
string str="mkdir -p sample_director/" + to_string(i);
system(str.c_str());
}
return 0;
}
And run your code with c++11 support
$ g++ -std=c++11 my_program.cpp
It doesn't work because dash doesn't support brace expansion (syntax like {1..10}). The system function doesn't care about the value of your SHELL, it always passes provided arguments to /bin/sh. And on Ubuntu /bin/sh refers to dash, which cannot handle brace expansion. On some other distributions (like Arch), /bin/sh is a symlink to bash, so your code will work fine.
If I were you, I wouldn't use system at all in this case. Boost::filesystem (or even mkdir/mkdirat) seems like a better option to me.
In MATLAB it is possible to call command programs written in C or C++. For example, I can use the following command to call a command program in Windows:
system('program.exe -i input_file1.txt -o output_file1.txt -m 1 ');
By doing so, I can invoke command line program directly from MATLAB. The problem I have now is that all the arguments must be fixed when I use the system function. If one argument, for example, is changeable, then using system function will fail. For instance,
for i=1:3
input_file_name = [num2str(i),'.txt'];
system('program.exe -i input_file_name -o output_file1.txt -m 1 ');
end
Then, how can I deal with this situation? Thanks.
You need to change your syntax slightly:
for i=1:3
input_file_name = [num2str(i),'.txt'];
system(['program.exe -i ' input_file_name ' -o output_file1.txt -m 1 ']);
end
input_file_name is the name of your variable in MATLAB so you can write verbatim in the string you pass to the system command.
More generally you can use sprintf to construct strings to pass to system, for example something like:
for n=1:3
system(sprintf('program.exe -i %d.txt -o output%d.txt -m 1',n,n));
end
(avoid using i and j as variables in MATLAB)