(shell-command "\"C:\\Documents and Settings\\ggustafson\\Desktop\\stuff\\ctags58\\ctags.exe\" -eR -f \"C:\\Documents and Settings\\ggustafson\\Desktop\\BlueTooth_7020\\TAGS\" \"C:\\Documents and Settings\\ggustafson\\Desktop\\BlueTooth_7020\"")
(message "\"C:\\Documents and Settings\\ggustafson\\Desktop\\stuff\\ctags58\\ctags.exe\" -eR -f \"C:\\Documents and Settings\\ggustafson\\Desktop\\BlueTooth_7020\\TAGS\" \"C:\\Documents and Settings\\ggustafson\\Desktop\\BlueTooth_7020\"")
Executing the top form gives me the error 'C:\Documents' is not recognized as an internal or external command, operable program or batch file.. Executing the output the second form puts into the *Messages* buffer works as intended (creates a tags file).
Why am I not getting the same results with both techniques? Does shell-command do something that changes the string before sending it to the shell? How can I use elisp to execute a string exactly as if I had pasted it into a command prompt?
shell-quote-argument does not work either as it produces a string that cannot be executed with either method:
(message (shell-quote-argument "\"C:\\Documents and Settings\\ggustafson\\Desktop\\stuff\\ctags58\\ctags.exe\" -eR -f \"C:\\Documents and Settings\\ggustafson\\Desktop\\BlueTooth_7020\\TAGS\" \"C:\\Documents and Settings\\ggustafson\\Desktop\\BlueTooth_7020\""))
"^\"\\^\"C:\\Documents and Settings\\ggustafson\\Desktop\\stuff\\ctags58\\ctags.exe\\^\" -eR -f \\^\"C:\\Documents and Settings\\ggustafson\\Desktop\\BlueTooth_7020\\TAGS\\^\" \\^\"C:\\Documents and Settings\\ggustafson\\Desktop\\BlueTooth_7020\\^\"^\""
shell-quote-argument is for quoting a single argument to a shell command (hence the name), not a shell command in its entirety.
Given that the error you were seeing suggested a lack of quoting somewhere, it seemed like a good idea to use the built-in command to deal with quoting rather than writing it manually and assuming you had the correct syntax.
Another alternative is using M-! to execute the command (or a similar one) interactively, figure out what gets accepted, and then afterwards use C-xM-: to obtain the elisp form.
I would suggest you to doublecheck both if executions are using same path, and therefore same ctags.exe. I think that might be the problem. You may want to use the full path to ctags.exe to make sure of that.
My ctags (Linux) gives me the same error if I use the -Re option on a normal shell; that is what makes me think that way.
I'd strongly recommend you use call-program instead of shell-command here, since you don't use any of the features of the shell, and it just gets in the way, forcing you to do quoting gymnastics to explain to the shell what you mean.
Related
I'm using Ruby on Linux.
I'd like to test for the existence of a command on the Linux system.
I'd like to not get back the output of the command that I'm testing for.
I'd also like to not get back any output that results from the shell being unable to find the command.
I want to avoid using shell redirection from within the command that I send to the shell. So something like system("foo > /dev/null") would be unsuitable.
I'm ok with using redirection if there is a way to do it from Ruby.
The simplest thing would be just to use system. Let's say you're looking for ls.
irb(main):005:0> system("which ls")
/bin/ls
=> true
If that's off the table, you could peek into the directories in ENV["PATH"] for the executable you're looking for. ENV["PATH"].split(":") would give you an array of directory names to check for the desired command. If you find a file with the right name, you may want to ensure it's an executable.
I want to avoid using shell redirection from within the command that I
send to the shell. So something like system("foo > /dev/null") would
be unsuitable. I'm ok with using redirection if there is a way to do it from Ruby.
system("exec which cmd", out: "/dev/null")
puts "Command is available." if ($?).success?
The exec is to explicitly avoid unnecessary forking in the shell.
As a sidenote type -P can be used instead of which, but it relies on Bash and may have surprising effects if script is ported to an environment with a different default shell.
I have a function (written below; source: TeX SX) that uses pipes in the shell which I'd like to use in vim command mode. It works as intended from the shell but returns an E34: No previous command error if entered in vim command mode. Full credit goes to jirislav in this post on TeX SX.
: | pdflatex -halt-on-error src.tex | grep '^!.*' -A200 --color=always
I'd very much like to have this shell functionality from the vim command line if anyone can help with that.
I tried the following from within vim command mode:
:! : | pdflatex -halt-on-error src.tex | grep '^!.*' -A200 --color=always
returns the E34 error. No pipes hides all compilation; however, it also doesn't output errors. Deleting 1 of 2 of the pipes also returns E34 errors for me.
I tried further troubleshooting to no success and here are some results of that. The help for :! says
a pipe '|' in {cmd} is passed to the shell, you cannot use it to append a vim command. See :bar
and :bar says (something that's referred to as escaping it out I think)
'|' can be used to separate commands, so you can give multiple commands in one line. If you want to use '|' in an argument, precede it with '\'.
I tried doing what :bar suggests, i.e.
:! : \| pdflatex -halt-on-error src.tex \| grep '^!.*' -A200 --color=always
The result is it hides everything, including compilation errors that I want to see. So I've come to the conclusion that I have no clue how to properly use shell pipes in vim command mode.
If you aren't a LaTeX user, all that the function is meant to do is the following. pdflatex compiles what's going on in vim into a pdf file. Enacting :! pdflatex % from vim's command mode outputs a whole slew of processing text and interrupts workflow; the grep in the function yanks out compilation errors, if they exist. The function, then, is meant to hide all output from pdflatex unless a compilation error occurs, in which case it outputs only the error and outputs it in red.
If anyone cared to explain the E34 error and why it doesn't work that would be appreciated, also.
Edit 1: This is now solved thanks to filbranden. Below there are a couple pictures attached of a minimal example should anyone come across this later.
vim file before input, output
Edit 2: Should you want to stick this in your .vimrc file, you'll need to escape out the pipe before grep, else the vimrc file defaults to thinking that pipe is a separator.
E34: No previous command
So the answer to your question was hiding in plain sight under :help E34, which redirects to the :! command.
(Vim pro-tip: whenever you get an error from Vim, ask for :help on the error code to get more context about it.)
The section on :! includes this passage:
Any ! in {cmd} is replaced with the previous external command. But not when there is a backslash before the '!', then that backslash is removed.
You did have a ! in your command, as part of the grep regular expression, ^!.*, so that was triggering the "history" behavior, trying to replace with the previously executed command. But since no command had executed at that point, the command failed with an error.
You can solve it by escaping the ! with a backslash, which Vim will remove before passing the command to the shell:
:! pdflatex -halt-on-error src.tex | grep '^\!.*' -A200 --color=always
But note that there are better ways to approach this problem! Let me cover some of them.
Using systemlist()
One great way to run external commands in Vim is to use the systemlist() function, which runs the command on a shell, captures its output, splits it into lines and returns a List with the resulting output lines.
So you could start with:
let latex_output = systemlist('pdflatex -halt-on-error src.tex')
And then use Vimscript commands to check for lines starting with ! to report to the user.
Note that, unlike with :!, the output of systemlist() is never displayed to the user (which means you don't switch back to seeing a terminal, possibly a blank one, and after the execution you don't have a "Hit enter prompt.) Which is great!
But that means you need to present that information to the user, when there are errors. A great way to do that is to use the quickfix window!
You can use the setqflist() function to set the contents of the quickfix window.
(For best results, you should set 'errorformat' appropriately, more on that later.)
Using vim-dispatch
If you don't like the part of running an external command (either through :! or systemlist()) that has it block Vim until the command execution is completed, then consider installing the vim-dispatch plug-in.
It can execute a command for you in background or in a separate terminal, so you're not blocked from editing. It also integrates with the :make command and the quickfix window.
Compiler configuration in vim-latex
Finally, the vim-latex plug-in (also known as latex-suite) has configurations to help you run pdflatex and report errors.
It includes a Vim :compiler configuration that will run pdflatex for you as a :make program. It also will set 'errorformat' to recognize the ! LaTeX Error string and recognize the line number of the errors, so you can jump to them directly from the quickfix list.
Note that vim-latex also has many other features to help you write LaTeX documents in Vim (besides managing the output generation through the compiler support.) You might want to check these other features as well.
(Since the plug-in has quite many features, I recommend reading the whole documentation to get you started on it.)
Also note that this plug-in is compatible with vim-dispatch (since vim-latex provides a compiler interface and vim-dispatch consumes it), so you can use both together if you like them both!
I have a bash script that executes a series of commands, some involving redirection. See cyrus-mark-ham-spam.
I want the script to have a test mode, where all the commands run are printed instead of executing them. As you can see, I have tried to do that by just putting "echo" on the front of each command in test mode.
Unfortunately this doesn't deal with redirection - any redirections are still done, so the program leaves lots of temp files littered about the place when run in test mode.
I have tried various ways to get round this, like quoting the whole command and passing it to a function that either prints it or runs it, but either the redirections work in test mode, or they don't work in run mode.
I thought this must have come up before, and wonder if there is a known solution which does not involve every command being repeated with an if TEST round the pair?
Please note, this is NOT a duplicate of show commands without executing them because neither that question, nor its answers, covers redirection (which is the essence of this question).
I see that it is not a duplicate but there is not general solution to this. You need to look at each command separately.
As long as the command doesn't use arguments enclosed in spaces, like
cmd -a -b -c > filename
, you can quote it:
echo 'cmd -a -b -c > filename'
But real life code is more complex, sure.
I wrote a script that's retrieving the currently run command using $BASH_COMMAND. The script is basically doing some logic to figure out current command and file being opened for each tmux session. Everything works great, except when user runs a piped command (i.e. cat file | less), in which case $BASH_COMMAND only seems to store the first command before the pipe. As a result, instead of showing the command as less[file] (which is the actual program that has the file open), the script outputs it as cat[file].
One alternative I tried using is relying on history 1 instead of $BASH_COMMAND. There are a couple issues with this alternative as well. First, it does not auto-expand aliases, like $BASH_COMMAND does, which in some cases could cause the script to get confused (for example, if I tell it to ignore ls, but use ll instead (mapped to ls -l), the script will not ignore the command, processing it anyway), and including extra conditionals for each alias doesn't seem like a clean solution. The second problem is that I'm using HISTIGNORE to filter out some common commands, which I still want the script to be aware of, using history will just make the script ignore the last command unless it's tracked by history.
I also tried using ${#PIPESTATUS[#]} to see if the array length is 1 (no pipes) or higher (pipes used, in which case I would retrieve the history instead), but it seems to always only be aware of 1 command as well.
Is anyone aware of other alternatives that could work for me (such as another variable that would store $BASH_COMMAND for the other subcalls that are to be executed after the current subcall is complete, or some way to be aware if the pipe was used in the last command)?
i think that you will need to change a bit your implementation and use "history" command to get it to work. Also, use the command "alias" to check all of the configured alias.. the command "which" to check if the command is actually stored in any PATH dir. good luck
Bash commands are available from an interactive tclsh session. E.g. in a tclsh session you can have
% ls
instead of
$ exec ls
However, you cant have a tcl script which calls bash commands directly (i.e. without exec).
How can I make tclsh to recognize bash commands while interpreting tcl script files, just like it does in an interactive session?
I guess there is some tcl package (or something like that), which is being loaded automatically while launching an interactive session to support direct calls of bash commans. How can I load it manually in tcl script files?
If you want to have specific utilities available in your scripts, write bridging procedures:
proc ls args {
exec {*}[auto_execok ls] {*}$args
}
That will even work (with obvious adaptation) for most shell builtins or on Windows. (To be fair, you usually don't want to use an external ls; the internal glob command usually suffices, sometimes with extra help from some file subcommands.) Some commands need a little more work (e.g., redirecting input so it comes from the terminal, with an extra <#stdin or </dev/tty; that's needed for stty on some platforms) but that works reasonably well.
However, if what you're asking for is to have arbitrary execution of external programs without any extra code to mark that they are external, that's considered to be against the ethos of Tcl. The issue is that it makes the code quite a lot harder to maintain; it's not obvious that you're doing an expensive call-out instead of using something (relatively) cheap that's internal. Putting in the exec in that case isn't that onerous…
What's going on here is that the unknown proc is getting invoked when you type a command like ls, because that's not an existing tcl command, and by default, that command will check that if the command was invoked from an interactive session and from the top-level (not indirectly in a proc body) and it's checking to see if the proc name exists somewhere on the path. You can get something like this by writing your own proc unknown.
For a good start on this, examine the output of
info body unknown
One thing you should know is that ls is not a Bash command. It's a standalone utility. The clue for how tclsh runs such utilities is right there in its name - sh means "shell". So it's the rough equivalent to Bash in that Bash is also a shell. Tcl != tclsh so you have to use exec.