Why does the behavior of mkdir differs on different Linux distros? - c++

I was trying to create folders named 1 2 3 4, using the C++ program below. I can successfully achieve that in RHEL.
However it created a folder named {1..4} in ubuntu 13.10.
Why does this happen? Thank you for helping me!
#include <cstdlib>
int main()
{
std::system("mkdir {1..4}");
}
It's a part of CPP unit test in our product. Yes, it's ugly. But I am afraid very few thing can be done in this situation.
You are right.
In RHEL,
sh -c 'echo {1..4}'
1 2 3 4
In Ubuntu
sh -c 'echo {1..4}'
{1..4}
So I use the program below instead. It works!
#include
int main()
{
std::system("bash -c 'mkdir {1..4}'");
}
seems system use sh by default....Thank you for your answer!

A bit of terminology: Linux has directories in its file systems, not "folders" (folders may appear visually on the desktop, but that is a desktop detail).
You don't need to use system(3) (which is running sh not bash!).
And POSIX sh don't know the {1..4} notation, hence the {1..4} string is passed verbatim to /bin/mkdir command (see mkdir(1) ...).
Run
sh -c 'echo {1..4}'
to test that sh don't understand the {1..4} notation.
(so it is a bug in your old RHEL, where perhaps /bin/sh is a symlink to /bin/bash while on Debian and Ubuntu it is a symlink to the more Posix compliant and faster /bin/dash)
Just use the mkdir(2) syscall and code
#include <cstdlib>
#include <cstdio>
#include <sys/stat.h>
#include <sys/types.h>
int main() {
for (int i=1; i<=4; i++) {
char buf[8];
snprintf(buf, sizeof(buf), "%d", i);
if (mkdir(buf, 0755))
{ perror("mkdir"); exit(EXIT_FAILURE); };
}
}
I hope you don't want to create a single directory named 1 2 3 4. It is possible and easy, but it really is poor taste. For your mental safety, use only letters, digits and underscores _ in directory names.
I am using snprintf(3) to convert an int to a character buffer. With C++11 you could use std::to_string and c_str ...
Read Advanced Linux Programming...
Using the mkdir(2) syscall instead of going thru a command invoked by system(3) has several important advantages:
it is much faster, you don't need to fork(2) a /bin/sh -c shell like system(3) should do.
it uses much less resources, since no additional process is fork-ed, so your program will still run when you have reached your limits (see setrlimit(2) ...)
it is more reliable. Should mkdir(2) fail you could (and should) handle the failure nicely. See errno(3) and strerror(3) ....

Related

What shell does std::system use?

TL;DR; I guess the shell that std::system use, is sh. But, I'm not sure.
I tried to print the shell, using this code: std::system("echo $SHELL"), and the output was /bin/bash. It was weird for me. So, I wanted to see, what happens if I do that in sh? And, the same output: /bin/bash. Also, if I use a command like SHELL="/usr/bin/something", to set the SHELL variable to another string, it will print the new string that I set to it (/usr/bin/something), and it looks it's not a good way to see what shell it's using. Then, I tried to check it, using the ps command, and the output was: bash, a.out, ps. It was weird to see bash in this list. So, I created a custom shell, and change the shell in gnome-terminal to it:
#include <iostream>
int main()
{
std::string input;
while (true)
{
std::string command;
std::getline(std::cin, command);
std::system(command.c_str());
}
}
Now, it's easier to test, and I think, the results is better.
Then, I tried to test the ps command again, but in the custom shell, and the results was: test_shell, ps.
It was weird again. How the shell isn't sh, nor bash? And, the final test I did was: echo $0. And, the results was sh, in both custom shell, and normal program.
Edit
It seems like /bin/sh is linked to /bin/bash (ll /bin/sh command's output is /bin/sh -> bash), and actually, it seems like the only difference between sh and bash is filename, and the files's contents are the same. I checked the difference between these files with diff command too:
$ xxd /bin/sh > sh
$ xxd /bin/bash > bash
$ diff sh bash
(+ Yes, $SHELL doesn't means the running shell (I didn't know that when I was testing, and I just wanted to see what happens))
The GNU sources (https://github.com/lattera/glibc/blob/master/sysdeps/posix/system.c) say
/bin/sh
So, whatever /bin/sh is hardlinked to is the shell invoked by std::system() on Linux.
(This is correct, as /bin/sh is expected to be linked to a sane shell capable of doing things with the system.)
According to cppreference.com, std::system
calls the host environment's command processor (e.g. /bin/sh, cmd.exe, command.com)
This means the shell used will depend on the operating system.
On any POSIX OS (including Linux), the shell used by std::system is /bin/sh. (Though as the OP points out, /bin/sh could be a symlink to another shell.)
As for the SHELL environment variable, as has been pointed out in the comments, this environment variable cannot be used to reliably identify the running shell program. SHELL is defined by POSIX to
represent a pathname of the user's preferred command language interpreter
(source)

system() call NOT targeting a sub-shell?

Working on a C++ Unix program executed on the command line (MacOs).
I call system("history -s SOMETHING") in it to add SOMETHING to the history of the user's shell, but I guess the call is opening a new sub-shell.
My question is : can I execute the system call on the "current" shell (the one used to run the program) ?
To be clear I want to find the SOMETHING in my shell history when I quit the program.
Thanks !
As far as I know, it's not possible in general.
If you're using bash, and since this is only for you:
Enable history appending in .bashrc:
shopt -s histappend
Launch a login bash shell in main:
system("bash -li -c 'history -s SOMETHING'");
and then refresh your history:
history -n
The history -n can be automated - you can execute it inside your prompt, for instance.
Figuring out how to do that left as an exercise.
(Disclaimer: I have only tried this in Ubuntu under the Windows Subsystem for Linux, but it should work very similarly on a Mac.)
It isn't possible. The usual work around -- not applicable if there is other wanted output -- is to make your program prints the wanted command and then execute it. For instance
#include <iostream>
int main() {
std::cout << "history -s SOMETHING\n";
return 0;
}
and then
eval $(/path/to/my/exe)
For ease of use, you can put that in a shell function
myfn() {
eval $(/path/to/my/exe)
}
that you can simply use
myfn

Include Git commit hash and/or branch name in C/C++ source

I would like to know how you can get a Git commit hash and/or other information into the contents of a C++ variable in the compiled binary without having it be part of the source that's tracked by Git.
I need to keep track of firmware release information in a compiled executable running on an embedded processor. Means to identify the particular release of the firmware binary such as meaningful filenames, MD5 checksums or even date/time stamps are not available in this closed environment (i.e., there is no filesystem).
One approach is to have the device's console output produce identifying text, such as 'Release 1.2.3', 'commit hash 1bc123...', or similar. The firmware release information is only of interest to maintenance personnel, so a trained operator could examine the console output. To implement this it could potentially involve manual editing of a version string, which is then compiled into the code and output to the console at program startup.
This is acceptable for major releases where a signoff workflow is used to double-check that the version information is correct. However, this being a manual process it is inherently unreliable. For example, what if the developer forgets to update the version information? - There is now a disconnect between the compiled code and its reported version string.
A workflow where the code is freshly compiled and downloaded each time the user wants to test the hardware is not practical in the situation in question, ie., it is quite onerous to update the firmware.
An automatic way of identifying the version of the code is thus required. In the situation in question, Git is used, and the developers regularly commit their work to feature branches. Displaying the Git commit hash, and perhaps also whether or not there are unstaged changes, would be a way of identifying the status of the source code used to compile the firmware.
The requirement is that I would like my application to have information available to it so that it is able to display:
"Git commit:[01abcdef...etc], branch: experimentalStuffDoNotRelease"
Thus, I would like to automatically include Git information, such as commit hash and branch, in the compiled C and/or C++ code.
The development environment has developers using both Windows and Linux, and uses Eclipse CDT with a relatively unsophisticated workflow of: check out; compile; download to the hardware.
I use a makefile, like so:
GIT_HASH=`git rev-parse HEAD`
COMPILE_TIME=`date -u +'%Y-%m-%d %H:%M:%S UTC'`
GIT_BRANCH=`git branch | grep "^\*" | sed 's/^..//'`
export VERSION_FLAGS=-DGIT_HASH="\"$(GIT_HASH)\"" -DCOMPILE_TIME="\"$(COMPILE_TIME)\"" -DGIT_BRANCH="\"$(GIT_BRANCH)\""
all:
g++ main.cpp $(VERSION_FLAGS)
When the makefile is run, the git hash and the time of compilation are both loaded into macros accessible within the source, like so:
#include <iostream>
int main(){
std::cerr<<"hash="<<GIT_HASH<<", time="<<COMPILE_TIME<<", branch="<<GIT_BRANCH<<std::endl;
}
Which gives output like:
hash=35f531bf1c959626e1b95f2d3e1a7d1e4c58e5ec, time=2017-05-18 04:17:25 UTC, branch=master
In Eclipse CDT, use a pre-build step to generate an include file containing the relevant information, and a conditional inclusion to check that the file was created:
Right-click the project
Select Properties
Expand the C/C++ Build
Select Settings In the Build Steps tab
Enter the following in the Command text box:
git log --pretty=format:'#define GIT_INFO_PRESENT%n static const char* GIT_INFO = "Version Information=[%H,%d]\r\n";' -n 1 > ../src/gitcommit.h
This will, upon build, create a file gitcommit.h that will be included in the source code. To customise it, adjust the string to your needs. (See https://git-scm.com/docs/pretty-formats)
As an example, I produce a debug output at the beginning of the main routine to inform the user of the commit and branch (not strictly needed knowing the commit, but certainly helpful):
Put this in the file, probably at the top
#if __has_include("gitcommit.h")
#include "gitcommit.h"
#else
static const char* GIT_INFO = "Git version information not present.\r\n";
#endif
To display the information somewhere in your code, do similar to this:
printf(GIT_INFO);
Note that I haven't, in this case, made the pre-build step a shell script or Windows/DOS .bat file, as I work often in Linux or Windows.
Note that this isn't tested in Windows.
In both cases, 'git' must be executable from the standard command line.
There is a dependency on provision of __has_include. This was intended to provide simplicity so that a default include file need not be provided.
Note that the gitcommit.h file's path should be discoverable by the compiler.
Usually as part of your build you run some command that generates something like that.
For example, git describe gives you something that you could use:
echo // auto generated version: > version.h
git describe > echo // auto generated version: > version.h
echo -e "#define VERSION " >> version.h
git describe >> version.h
For example x264 use this simple script to generate it:
if [ -d .git ] && command -v git >/dev/null 2>&1 ; then
localver="$(($(git rev-list HEAD | wc -l)))"
if [ "$localver" -gt 1 ] ; then
ver_diff="$(($(git rev-list origin/master..HEAD | wc -l)))"
ver="$((localver-ver_diff))"
echo "#define X264_REV $ver"
echo "#define X264_REV_DIFF $ver_diff"
if [ "$ver_diff" -ne 0 ] ; then
ver="$ver+$ver_diff"
fi
if git status | grep -q "modified:" ; then
ver="${ver}M"
fi
ver="$ver $(git rev-list -n 1 HEAD | cut -c 1-7)"
version=" r$ver"
fi
fi
echo "#define X264_VERSION \"$version\""
echo "#define X264_POINTVER \"0.$ver\""
This will generate something like:
#define X264_VERSION " r2708 86b7198"
#define X264_POINTVER "0.148.2708 86b7198"
Here's simple solution if you need git hash and local modifications flag only:
$ cat update-version-info.sh
#!/bin/sh
version=$(git describe --always --dirty --tags)
echo "#define GIT_VERSION \"$version\"" > git-version.h
$ cat 1.c
#include <stdlib.h>
#include <stdio.h>
#include "git-version.h"
int main() {
#ifdef GIT_VERSION
printf("%s\n", GIT_VERSION);
#endif
return 0;
}
$ ./1
ee4f307-dirty
Based on #Richard's answer and my fixes for qmake/Qt, here is the solution I use:
With Qt 5.14 the following lines in .pro file work for me:
GIT_HASH="\\\"$$system(git -C \""$$_PRO_FILE_PWD_"\" rev-parse --short HEAD)\\\""
GIT_BRANCH="\\\"$$system(git -C \""$$_PRO_FILE_PWD_"\" rev-parse --abbrev-ref HEAD)\\\""
BUILD_TIMESTAMP="\\\"$$system(date -u +\""%Y-%m-%dT%H:%M:%SUTC\"")\\\""
DEFINES += GIT_HASH=$$GIT_HASH GIT_BRANCH=$$GIT_BRANCH BUILD_TIMESTAMP=$$BUILD_TIMESTAMP
In your code you can check the revision like this:
int main(int argc, char *argv[])
{
QStringList args;
for (int i = 0; i < argc; i++)
args << QString(argv[i]);
if (args.contains("-v") || args.contains("--version")) {
std::cout << QString("branch: %1, version: %2, built_at: %3").arg(GIT_BRANCH).arg(GIT_HASH).arg(BUILD_TIMESTAMP).toUtf8().constData() << std::endl;
return 0;
}
// ...
}
A C file or a C++ file can be generated by some program (for example, some shell script on Linux, or some GNU awk script, or your C program running system or popen(3) running some git command).
You just configure your build automation tool (e.g. your Makefile if you use GNU make, or your build.ninja file if you use ninja) appropriately.
Both Bismon and RefPerSys are doing so and keep their git id inside the obtained executable (displaying it when invoked with --version). Note: both are projects I created.
PS a different question is how to configure your IDE to run a particular build automation tool. This is specific to your IDE. But Eclipse CDT FAQ offers an insight.

using system() in C++;does not work

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.

Using C++ commands directly from command line

I wanted to ask Is there any way by which you can simply use 'std::cout << "Hello world";' directly from command line.
As in like if you have python installed,
$python
print 'Hello world'
Hello world
Can something like this be done for C++ by any means?
There is cling which is an interactive C++ shell. I haven't used it but it may fit your needs.
Here is a bit of a more expanded response: it took me a while get cling built, primarily because I wasn't following instructions exactly and set up the source tree to include things it should have included. Here are the steps I used to build and install cling (building a release version didn't work for me):
svn co -r 191429 http://llvm.org/svn/llvm-project/llvm/trunk llvm
cd llvm/tools
svn co -r 191429 http://llvm.org/svn/llvm-project/cfe/trunk clang
git clone http://root.cern.ch/git/cling.git
cd ..
cat tools/cling/patches/*.diff | patch -p0
./configure --enable-targets=host --prefix=/opt/cling
mk -j8
sudo - make install
After this, I got a C++ shell. Of course, my first interaction wasn't entirely successful because the cling page says that it includes some headers. I had assumed that it would surely include <iostream> but that wasn't the case. Here is a simple interaction that works, though:
$ /opt/cling/bin/cling
****************** CLING ******************
* Type C++ code and press enter to run it *
* Type .q to exit *
*******************************************
[cling]$ #include <iostream>
[cling]$ std::cout << "hello, world\n";
hello, world
[cling]$ #include <iterator>
[cling]$ std::copy(s.begin(), s.end(), std::ostream_iterator<char>(std::cout));
hello, world
[cling]$ .q
Python is an interpreted language:
http://en.wikipedia.org/wiki/Interpreted_language
C++ is a compiled language:
http://en.wikipedia.org/wiki/Compiled_language
So no.
Sorry
I don't think so, C++ needs to be compiled first, Python is an interpreted language.
So you can't have a script that calls
cout<<"Hello world";
without first compiling the code.
If you're using GCC and Cygwin or Linux, you could do something like the following:
echo -e '#include <iostream>\n int main(void) {std::cout << "Hello world";}'|g++ -xc++ - && ./a.out && rm a.out