Using search/replace in filename output in build system - sublimetext3

How can I search/replace the output filename in my build system command? For example if the file I'm editing was called file_src, then I would want my build system to output it as file_build.
"shell_cmd": "my_command ${file} > ${file_name_but_search_replaced}"

Variable expansions in build systems are performed using the same underlying mechanism as that which is used in snippet substitutions, which is:
${var_name/regex/format_string/options}
As outlined in the link above, in snippets the variable named can be snippet fields or other special variables that apply only in snippets such as $SELECTION. Inside of a sublime-build file, the build variables are used instead.
How you might apply that depends on your needs and the filenames involved. For example:
{
"shell_cmd": "echo '${file_path}/${file_name/_src/_build/}'"
}
The thing to keep in mind is that the replacement will apply to the first match in the file (unless you specify the option to make it global, in which case it applies to all), so here the expansion is the path of the file followed by the name of the file with the substitution in just that field.
That makes sure that only the filename is modified in cases where the path might also contain the regex. Depending on your use case that may not matter (or be desirable), in which case you could apply it to $file instead.

Related

How can I get the name of the sourced script in tcsh?

I'm looking for a way to get the name of a script that's being sourced from another script that's being executed in tcsh.
If I needed to the the name of a script being executed (not sourced), it's $0. If I need to get the name of a script that's being sourced from the command line, I can get it from $_. But when an executed script sources a script, I get an empty value for $_ in the sourced script, so I can't get the script name or pathname from that.
I'm looking for a non-manual method for getting that information.
There isn't really anything for this; source is mostly just a way to read the file and run it in the current scope.
However, it does accept arguments; from the tcsh manpage:
source [-h] name [args ...]
The shell reads and executes commands from name. The commands
are not placed on the history list. If any args are given,
they are placed in argv. (+) source commands may be nested; if
they are nested too deeply the shell may run out of file
descriptors. An error in a source at any level terminates all
nested source commands. With -h, commands are placed on the
history list instead of being executed, much like `history -L'.
So for example source file.csh file.csh will have argv[1] set to file.csh.
Another option is to simple set a variable before the source command:
set src = "file.csh" # Will be available in file.csh
source file.csh
If you can't or don't want to modify the source call then you're out of luck as far as I know. (t)csh is an old crusty shell with many awkward things, large and small, and I would generally discourage using it for scripting unless you really don't have any option available.
$_ simply gets the last commandline from history; maybe, very maybe it's possible to come up with a super-hacky solution to (ab)use the history for this in some way, but it seems to me that just typing the filename twice is a lot easier.

copy and append specific lines to a file with specific name format?

I am copying some specific lines from one file to another.
grep '^stringmatch' /path/sfile-*.cfg >> /path/nfile-*.cfg
Here what's happening: its creating a new file called nfile-*.cfg and copying those lines in that. The file names sfile- * and nfile- * are randomly generated and are generally followed by a number. Both sfile-* and nfile-* are existing files and there is only one such file in the same directory. Only the number that follows is randomly generated. The numbers following in sfile and nfile need not be same. The files are not created simultaneously but are generated when a specific command is given. But some lines from one file to the another file needs to be appended.
I'm guessing you actually want something like
for f in /path/sfile-*.cfg; do
grep '^stringmatch' "$f" >"/path/nfile-${f#/path/sfile-}"
done
This will loop over all sfile matches and create an nfile target file with the same number after the dash as the corresponding source sfile. (The parameter substitution ${variable#prefix} returns the value of variable with any leading match on the pattern prefix removed.)
If there is only one matching file, the loop will only run once. If there are no matches on the wildcard, the loop will still run once unless you enable nullglob, which changes the shell's globbing behavior so that wildcards with no matches expand into nothing, instead of to the wildcard expression itself. If you don't want to enable nullglob, a common workaround is to add this inside the loop, before the grep;
test -e "$f" || break
If you want the loop to only process the first match if there are several, add break on a line by itself before the done.
If I interpret your question correctly, you want to output to an existing nfile, which has a random number in it, but instead the shell is creating a file with an asterisk in it, so literally nfile-*.cfg.
This is happening because the nfile doesn't exist when you first run the command. If the file doesn't exist, bash will fail to expand nfile-*.cfg and will instead use the * as a literal character. This is correct behaviour in bash.
So, it looks like the problem is that the nfile doesn't exist when you start your grep. You'll need to create one.
I'll leave code to others, but I hope the explanation is useful.

How do I get the relative path of a file in a project?

I want to create a build system for my app where it will open a url to the target file. For example, if I run the build on a project file components/flower.html, it should run
open http://localhost:8080/app/components/flower.html
The list of variables for ST don't have relative path. so the closest I get is
http://localhost:8080/app//dev/myproject/components/flower.html
It contains the full path. Perhaps there is an easy way to remove the /dev/myproject part?
This is the build setting I want to further customise:
"cmd": ["open", "http://localhost:8080/app/${file_path}"]
If we look at the documentation on Build Systems, we see that we can use snippet substitution in the variables used in the build system. This is really handy when the built in variables don't quite meet our needs.
Therefore, we can replace the project dir with nothing to get a relative path.
I find the easiest way to test substitutions is using a snippet for $SELECTION, so you can just change the selected text and try a different test case, without needing to worry about saving the file with different names or running the build system and waiting for the results.
The substitution is done with regular expressions, where forward slashes need to be escaped, as they have special meaning. One slash after the variable name, one slash after the find regex pattern, one slash after that, followed by the replacement pattern, followed by a slash to indicate the end of the replacement pattern and optionally followed by some regex flags. Therefore, the snippet I'm using is:
<snippet>
<content><![CDATA[
${SELECTION/^\/dev\/myproject\///}
]]></content>
<!-- Optional: Set a tabTrigger to define how to trigger the snippet -->
<!-- <tabTrigger>hello</tabTrigger> -->
<!-- Optional: Set a scope to limit where the snippet will trigger -->
<!-- <scope>source.python</scope> -->
</snippet>
This just matches from the beginning of the string (^), then the literal /dev/myproject/ (unfortunately variables can't be used in regex patterns, otherwise we could maybe use $project_path) and replaces it with nothing. As we are only expecting one match, we don't need to use the global regex modifier flag.
The output we get from that with a selection of /dev/myproject/components/flower.html is:
components/flower.html
Which seems to be what we want, because with http://localhost:8080/app/ preceding it, it becomes http://localhost:8080/app/components/flower.html.
So, now we can just take the variable part out the snippet, and replace SELECTION with file_path, so it will operate on the current file's path instead of the selection, just like you had originally, and plug that into your build system:
"cmd": ["open", "http://localhost:8080/app/${file_path/^\/dev\/myproject\///}"]

Own simple template system in vim - include file

I've read vim-wiki about dynamic templates and I want similar, simple "template-system". I've created a function:
function! Read_template(file)
execute '0r /home/zsolt/.vim/skeletons/'.a:file
%substitute#\[:EVAL:\]\(.\{-\}\)\[:END:\]#\=eval(submatch(1))#ge
%substitute#\[:READ:\]\(.\{-\}\)\[:END:\]#??????#ge
endfunction
I want to include a file from a template. The EVAL works well but how can I solve the READ function? It isn't important to eval the included file.
An example:
main.tex:
\documentclass[a4paper]{article}
....
exam.tex:
% Created [:EVAL:]strftime('%Y. %B. %d.')[:END:]
[:READ:]/path/of/main/main.tex[:READ:]
I exec Read_template("exam.tex") and want that exam.tex includes main.tex.
How can I do this?
You'll need to read the file and insert its contents. As you cannot use :read (it will read entire lines and cannot be called from within a substitution), you have to use the lower-level readfile() Vimscript function, like this:
%substitute#\[:READ:\]\(.\{-\}\)\[:END:\]#\=join(readfile(submatch(1)),"\n")/#ge
You'll have to parse each line imported and apply what needs be :
- expression substitution
- inclusion of other templates, etc. (which will mean that you'll have to remove and add lines on the fly. In the last version of mu-template template expansion engine, the expansion is done in-memory)
FYI, my work of mu-template already has this feature: http://code.google.com/p/lh-vim/wiki/muTemplate#Completely_useless_recursive_example

exec() security

I am trying to add security of GET query to exec function.
If I remove escapeshellarg() function, it work fine. How to fix this issue?
ajax_command.php
<?php
$command = escapeshellarg($_GET['command']);
exec("/usr/bin/php-cli " . $command);
?>
Assume $_GET['command'] value is run.php -n 3
What security check I can also add?
You want escapeshellcmd (escape a whole command, or in your case, sequence of arguments) instead of escapeshellarg (escape just a single argument).
Notice that although you have taken special precautions, this code allows anyone to execute arbitrary commands on your server anyways, by specifying the whole php script in a -r option. Note that php.ini can not be used to restrict this, since the location of it can be overwritten with -c. In short (and with a very small error margin): This code creates a severe security vulnerability.
escapeshellarg returns a quoted value, so if it contains multiple arguments, it won't work, instead looking like a single stringesque argument. You should probably look at splitting the command up into several different parameters, then each can be escaped individually.
It will fail unless there's a file called run.php -n 3. You don't want to escape a single argument, you want to escape a filename and arguments.
This is not the proper way to do this. Have a single PHP script run all your commands for you, everything specified in command line arguments. Escape the arguments and worry about security inside that PHP file.
Or better yet, communicate through a pipe.

Resources