I have an application that stores some information in a *.conf file, something like this:
[DEFAULT]
somevar = blablabla
othervar = blebleble
Is there a usual place on a linux system where I can put this file when it is being installed or should I put it on a place related to the application?
Thanks.
System-wide configuration is stored under /etc. Per-user configuration is stored in a hidden file in the user's home directory.
Depends what your application is.
If it is the usual F/LOSS, then global config goes under /etc/, per-user goes under $HOME/. As per convention, config files under $HOME have the same name as under /etc/ but start with . - that means they are hidden and do not show up (ls) unless you tell to specifically show them (ls -a, ls -A). If you have multiple configs, then use subdirectory under /etc/ or $HOME (again with the .). Check for example what Debian Policy Manual says about that.
If this is some commercial application which is going to be installed manually/semi-automatically somewhere under /opt/<progname>, then put the configs (you would likely have only global ones) under /opt/<progname>/etc. General rule in the case is to mimic the usual *NIX hierarchy (except for $HOME), but rooted under your /etc/<progname> subdirectory.
Also note that Windows-style .ini files are not very well accepted on *NIX systems: it is hard to work with them from command line. If possible, use the properties-style config file. E.g. the config you have quoted above would look like:
DEFAULT.somevar = blablabla
DEFAULT.othervar = blebleble
Related
I feel like I'm missing something very basic so apologies if this question is obtuse. I've been struggling with this problem for as long as I've been using the bash shell.
Say I have a structure like this:
├──bin
├──command (executable)
This will execute:
$ bin/command
then I symlink bin/command to the project root
$ ln -s bin/command c
like so
├──c (symlink to bin/command)
├──bin
├──command (executable)
I can't do the following (errors with -bash: c: command not found)
$ c
I must do?
$ ./c
What's going on here? — is it possible to execute a command from the current directory without preceding it with ./ and also without using a system wide alias? It would be very convenient for distributed executables and utility scripts to give them one letter folder specific shortcuts on a per project basis.
It's not a matter of bash not allowing execution from the current directory, but rather, you haven't added the current directory to your list of directories to execute from.
export PATH=".:$PATH"
$ c
$
This can be a security risk, however, because if the directory contains files which you don't trust or know where they came from, a file existing in the currently directory could be confused with a system command.
For example, say the current directory is called "foo" and your colleague asks you to go into "foo" and set the permissions of "bar" to 755. As root, you run "chmod foo 755"
You assume chmod really is chmod, but if there is a file named chmod in the current directory and your colleague put it there, chmod is really a program he wrote and you are running it as root. Perhaps "chmod" resets the root password on the box or something else dangerous.
Therefore, the standard is to limit command executions which don't specify a directory to a set of explicitly trusted directories.
Beware that the accepted answer introduces a serious vulnerability!
You might add the current directory to your PATH but not at the beginning of it. That would be a very risky setting.
There are still possible vulnerabilities when the current directory is at the end but far less so this is what I would suggest:
PATH="$PATH":.
Here, the current directory is only searched after every directory already present in the PATH is explored so the risk to have an existing command overloaded by an hostile one is no more present. There is still a risk for an uninstalled command or a typo to be exploited, but it is much lower. Just make sure the dot is always at the end of the PATH when you add new directories in it.
You could add . to your PATH. (See kamituel's answer for details)
Also there is ~/.local/bin for user specific binaries on many distros.
What you can do is add the current dir (.) to the $PATH:
export PATH=.:$PATH
But this can pose a security issue, so be aware of that. See this ServerFault answer on why it's not so good idea, especially for the root account.
I have a multitude of commands I'd like to run not in the current directory, but in the project root directory. i.e. going up directories until I reach some indication of a root, like .git directory for example.
For example running vimgrep -r (recursive) on all my project, or running tags generation recursively on whole project.
How do I get that path? The only close indication I found is this:set tags=./tags;~/Projects
But that just saves the string as it is into tags. Assigning something similar but for the use case described, gets me the string verbatim.
Any help is greatly appreciated!
Thanks!
Avoid the idea of "changing the working directory" or distinguishing between "working directory and project root", because almost no tool is prepared to properly handle those concepts.
The only tools that do (e.g. git) are those that don't care about the current directory to begin with.
Otherwise, it's madness to try to get everything working without bad side effects. "Working directory" is a concept too fundamental to even attempt to change within a running program.
The best approach is open a new Vim sessions inside directories where you want to do "local" things - and switch back to the "project" session to run project commands. Vim will protect you from accidentally overwriting changes in another session.
The alternative is to wrap commands in shells so they can have their "own" working directories, e.g.:
:!cd ../../..; ctags -R
(Which would allow you to regenerate tags file for the project, and not just the current dir)
or:
:!cd ../../..; grep -r foo **/*
But any output with file names would be relative to that root directory, and not the current one.
So you may prefer to do:
:!cd ../../..; vim
which creates a new Vim session within the current one, but in the context of the root directory.
Or, you may prefer the reverse (assuming Vim is running in the project root):
:!cd $(dirname %); vim
Which lets you work in the directory of the current file - and you'd have to exit to the main session to run project-wide tools again.
So instead of "changing" directories, you're "changing vim sessions" (either by having 2 sessions or "nesting" one in another like above).
I use a local_vimrc plugin to set project related variables. Then, I use (/write) plugins that rely on (buffer/project)-local variables to do stuff. (Unfortunately, most plugin out there rely of global variables which is not the best choice to specialize their behaviour to the current project in multi-projects sessions)
Regarding ctags generation, in use lh-tags that requires a few variables to be set.
Regarding grepping, as other, I usually start from the current directory which is often the root directory of my project. But you could also easily have a plugin/command that would run something like:
exe "vimgrep -r ".pattern." ".
\ map(file_extensions,
\ string(lh#option#get('project_root_directory').'/**').'v:val')
EDIT:
If you don't want other configuration files, and if the .git/ directory is enough to identify your project root directory, then, you can have this kind of function to get your project root directory:
function! ProjectRootDirectory()
return fnamemodify(finddir('.git', '.;'), ':h')
endfunction
Then when you'll run ctags, you'll have to execute ctags from the result of this vim function. I don't know which plugin you use to run ctags, at this moment. My lh-tags doesn't support functions through its configuration variables. It can easily been added if need be.
However, I don't see a simple way to configure &tags once from the .vimrc in order to configure this setting on a per project basis.
I personally like to keep it simple and have my current directory be my project root. I can use % to represent the current file in commands, e.g. :!git add %. Along with % you can use filename modifiers, e.g. :e %:h/foo.txt. See :h filename-modifiers.
However you mentioned that you use CtrlP and you like the way it changes the current directory. This means you need to be a bit more creative.
Here is what I would recommend:
Update your tags via git hooks. See Effortless Ctags with Git
If your tags are in .git/tags fugitive.vim will automatically setup these tags for you.
Use :Ggrep which uses git grep so it already know about your project root directory and as a bonus is much faster than :vimgrep.
Running arbitrary commands from the root is trickier. I use projectionist to manage my projects. Projectionist provides the command, :ProjectDo, which does exactly what you want.
Now a word of caution: Vim has no understanding of a "project". The closest thing to is 'exrc' option (See :h 'exrc') which is pretty lame.
I am looking for a generic command line solution that would allow me to add or modify a configuration option inside a config file (INI-like format).
Most Linux configuration files use a INI-like format, with # and ; as comment and with option=value.
Mainly I am looking for something that would take filename, option and value, and that will change the config to match this.
I want to use this to write some auto-deployment scripts. I have no problem on using tools that are not installed by default on Debian or Ubuntu as long they do exist in the default distribution repositories (as I can do an apt-get install xxx, if needed).
Example: change-config /etc/default/nginx ULIMIT '"-n 4096"'
The expected result would be to have ULIMIT="-n 4096" inside the nginx file. Obviously if it does already exists and have the same value, it should do nothing. If it exists, commenting the old line would be fine and adding the new one.
As a note, these config files can have spaces/tabs between parameters so if you have ULIMIT = "..." is still the same command. That's why I was looking for something better than sed as there are plenty of corner cases to evaluate.
Also, I don't want to reinvent the wheel, and I doubt that I am the first one to look for a solution to this kind of problem.
git config is actually a semi-generic INI interface.
❱ git config --file=/etc/default/nginx somegroup.ULIMIT '-n 4096'
❱ cat /etc/default/nginx
[somegroup]
ULIMIT = -n 4096
❱ git config --file=/etc/default/nginx somegroup.ULIMIT
"-n 4096"
It doesn't support adding top-level keys, though. All keys have to be placed in an INI style group, hence the "somegroup." above. That makes it unsuitable for your task, but I thought I'd mention it here for others finding their way here.
Try crudini. BTW I think this file is a shell file rather than an ini file,
but crudini can still work in this case:
crudini --set /etc/default/nginx '' ULIMIT '"-n 4096"'
Augeas / augtool aims to do this, although you'll need the right lens for the type of file you're after (you can also write your own), for example, the Nginx lens.
It also has an API if required.
Manual files in Linux are stored in /usr/share/man. Before, my application could only be installed by a root user and it put the manual files in this directory. Now, I want to enable non-root installation; to achieve this, all my data and configuration files will be installed under ~/<appname>/. However, manual files copied to home will no longer be accessible by man command.
What are the usual workarounds to this problem?
I've thought in creating a "man" command in my application that runs man -M /<man_path>/<appname>/ (as this is easier to users than running the command by themselves). Is this a good option?
Thanks in advance.
[spatel#ap4004 appname]$ export MANPATH=/home/spatel/appname/man
[spatel#ap4004 appname]$ manpath
/home/spatel/appname/man/en:/home/spatel/appname/man
Other workaround is command alias
[spatel#ap4004 appname]$ alias man='man -M /home/spatel/appname/man'
[spatel#ap4004 appname]$ alias man
alias man='man -M /home/spatel/appname/man'
You'll need to use manpath command.
man has new behaviour by default (at least on Fedora 14 and on) that it searches in paths corresponding to PATH environment variable, i.e. for PATH=/xyz/bin it searches /xyz/bin/man, /xyz/share/man and other nearby places. Unless MANPATH is set.
You need to unset MANPATH at the end of your .bash_profile, some startup scripts in /etc may set it to spite you.
If you don't specify an explicit path list with -M or MANPATH, man develops its own path list based on the contents of the configuration file /etc/man.config. The MANPATH statements in the configuration file identify particular directories to include in the search path.
Furthermore, the MANPATH_MAP statements add to the search path depending on your command search path (i.e. your PATH environment variable). For each directory that may be in the command search path, a MANPATH_MAP statement specifies a directory that should be added to the search path for manual page files. man looks at the PATH variable and adds the corresponding directories to the manual page file search path. Thus, with the proper use of MANPATH_MAP, when you issue the command man xyz, you get a manual page for the program that would run if you issued the command xyz.
In addition, for each directory in the command search path (we'll call it a "command directory") for which you do not have a MANPATH_MAP statement, man automatically looks for a manual page directory "nearby" namely as a subdirectory in the command directory itself or in the parent directory of the command directory.
You can disable the automatic "nearby" searches by including a NOAUTOPATH statement in /etc/man.config.
I have a file called x.sh that I want to execute. If I run:
x.sh
then I get:
x.sh: command not found
If I run:
./x.sh
then it runs correctly. Why do I have to type in ./ first?
Because the current directory is not into the PATH environment variable by default, and executables without a path qualification are searched only inside the directory specified by PATH. You can change this behavior by adding . to the end of PATH, but it's not common practice, you'll just get used to this UNIXism.
The idea behind this is that, if executables were searched first inside the current directory, a malicious user could put inside his home directory an executable named e.g. ls or grep or some other commonly used command, tricking the administrator to use it, maybe with superuser powers. On the other hand, this problem is not much felt if you put . at the end of PATH, since in that case the system directories are searched first.
But: our malicious user could still create his dangerous scripts named as common typos of often used commands, e.g. sl for ls (protip: bind it to Steam Locomotive and you won't be tricked anyway :D).
So you see that it's still better to be safe that, if you type an executable name without a path qualification, you are sure you're running something from system directories (and thus supposedly safe).
Because the current directory is normally not included in the default PATH, for security reasons: by NOT looking in the current directory all kinds of nastiness that could be caused by planting a malicious program with the name of a legitimate utility can be avoided. As an example, imagine someone manages to plant a script called ls in your directory, and that script executes rm *.
If you wish to include the current directory in your path, and you're using bash as your default shell, you can add the path via your ~/.bashrc file.
export PATH=$PATH:.
Based on the explanation above, the risk posed by rogue programs is reduced by looking in . last, so all well known legitimate programs will be found before . is checked.
You could also modify the systemwide settings via /etc/profile but that's probably not a good idea.
Because current directory is not in PATH (unlike cmd in Windows). It is a security feature so that malicious scripts in your current directory are not accidentally run.
Though it is not advisable, to satisfy curiosity, you can add . to the PATH and then you will see that x.sh will work.
If you don't explicitly specify a directory then the shell searches through the directories listed in your $PATH for the named executable. If your $PATH does not include . then the current directory is not searched.
$ echo $PATH
/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/X11/bin
This is on purpose. If the current directory were searched then the command you type could potentially change based on what directory you're in. This would allow a malicious user to place a binary named ls or cp into directories you frequent and trick you into running a different program.
$ cat /tmp/ls
rm -rf ~/*
$ cd /tmp
$ ls
*kaboom*
I strongly recommend you not add . to your $PATH. You will quickly get used to typing ./, it's no big deal.
You can't execute your file by typing simply
x.sh
because the present working directory isn't in your $PATH. To see your present working directory, type
$ pwd
To see your $PATH, type
$ echo $PATH
To add the current directory to your $PATH for this session, type
$ PATH=$PATH:.
To add it permanently, edit the file .profile in your home directory.