How can I embed a command like mysql -sN -e "query;" inside a perl script so that my shell will be the one making the database connection. The query is a little complicated query which runs perfectly from the command line but when I set it up in my perl program, i get a bunch of errors like "string found where operator expected" , "bareword found where operator expected" and syntax error. Any idea how to do this without making giving perl access to the database?
You can use back quotes, the example below will place the output of the OS ls -l command into content. Assuming you know the risks of what you are doing.
#!/usr/bin/perl
use strict;
my $content=`ls -l`;
print $content;
Related
How can I call an external program from mysql?
I am a complete beginner at this, on Linux Mint 20, I created a database of all my video files, the paths of the videos are all listed in a table.
I can access the DB using Bash with:
mysql -u root -proot -e "use collection; select path from videos where path Like '%foo%' or path Like '%bar%'"
To search for what I want, but now I want to pipe the chosen vid(s) to MPV/VLC, whatever.
Apart from the fact I am doing it as root, am I going about this the wrong way?
I just want to perform quick searches in a terminal, then fire up the vid(s).
Thanks a lot, folks.
If I'm understanding correctly. You want to query your db for a specific type of file or path and then you want to use the result of your query to open up the files?
You don't open the program from MySQL, but you could open it from bash.
Figure out what the bash command is to open that program and use the output of your query to run over a loop in bash to open, one by one, the results you got from your query.
Alternatively you can output the results to a temporary file and read from it with bash:
mysql -user -pass -e "YOUR QUERY" > /tmp/output.txt
If you can get the right output in your output.txt file, I would look into reading from that file in bash with a loop. Something like:
while IFS= read -r line
do
mpv "$line"
done < output.txt
Within tclsh I can run the following and get the expected output:
% exec bash -c "ulimit -v"
50331648
However within a Tcl script nothing is returned. No error, no output, nothing. There's clearly some gotcha with exec'ing 'bash -c' that I can't work out.
Alternatively, is there a native way in Tcl that I can get the system's memory limit to avoid having to do it this way in the first place?
In an interactive tclsh session, the REPL helpfully prints the output of commands/expressions. That's not the case in a non-interactive program.
exec returns the output of the command: you just need to capture it with the usual command substitution:
set output [exec bash -c "ulimit -v"]
puts $output
The code that you wrote should work; I can't identify why bash would silently fail to run ulimit -v. Even if the script was running in an environment where that was privileged information (why!?) one would still expect to get an error message of some form. That's a very weird problem!
Tcl's base command set doesn't expose any access to memory limits, whether for reading or writing. The simplest workaround that doesn't call an external program is the tclbsd package (apparently it mostly works on most other Unixes as well), which exposes a command that should help:
package require BSD
set limit [bsd::rlimit get soft virtual]
Sound as lazy as it is I was wondering if it's possible to open a file with sublime using (command line) and in the same command define the expected syntax.
Lets say on a mac we have the subl command installed, so running $ subl .bash_something will open the .bash_something then we have to chose the "shel script(bash)" syntax from the list. what would be really nice (for laze me) is to include the syntax to the command as an argument. i.e.
$ subl -x bash .bash_something
or something like that. this obviously doesn't work but I was wondering if there is similar solution or if its possible to include one
Unfortunately, there is no way that I can find to dynamically set the syntax from the command line. subl has the --command option, which allows you to run a Sublime command while loading the file, directory, or project indicated. However, the command to change the syntax of a view - set_file_type - takes an argument of the form ("syntax": "Packages/PackageName/SyntaxName.sublime-syntax") (or SyntaxName.tmLanguage). As far as I've been able to tell, you simply can't pass arguments to commands run via the command line. I've opened an issue to request an enhancement.
Now, this doesn't mean that all is lost. If you have just a few filetypes that are unknown to Sublime, open them, then select View -> Syntax -> Open all with current extension as... and select the syntax you want. If for some reason this isn't sufficient, or would like finer-grained control over exactly which filenames (not just which extensions) get opened as what, check out the ApplySyntax plugin. It allows you to use regexes to open exactly which file patterns you define as what syntax.
Commands can take arguments in Sublime 3 now. I was able to achieve this functionality with a bash function.
You can pass arguments to the --command option with inline JSON and escaped quotes. This command will change the syntax to Bash for the current active file in Sublime:
subl --command "set_setting {\"setting\": \"syntax\", \"value\": \"Packages/ShellScript/Shell-Unix-Generic.sublime-syntax\"}"
I created a simple bash function and sourced it in my .bash_profile to wrap these two commands together to activate/open a file then change the synax:
function subl_bash() {
subl "$1" && subl --command "set_setting {\"setting\": \"syntax\", \"value\": \"Packages/ShellScript/Shell-Unix-Generic.sublime-syntax\"}"
}
Is it possible to run some interactive shell from inside tclsh? Obviously it's easy to run an interactive shell such as bash or tclsh from inside bash, but I have not found a way to do the reverse.
If I run "exec tclsh" or "exec bash" from inside tclsh I don't get a prompt until I type "exit" and hit enter, or I use "ctrl-C" which kills the parent tclsh.
I would prefer not to use an external package, if at all possible.
Provided you don't want to pass values (other than the exit code) back to the calling Tcl code you can do it pretty easily by redirecting the standard channels so that Tcl doesn't capture them:
exec tclsh <#stdin >#stdout 2>#stderr
This will work for pretty much any subprocess (I've just tested it with vi) and is what tclsh actually does magically for you in interactive mode if it decides to try running a subprocess.
If you want to do anything more complex than that, you probably need to look into using Expect as there's a very long list of tricky gotchas otherwise.
I have written a backup script that uses expect to automate rsync.
To make sure all files get backed up, I use rsync's --rsync-path="sudo rsync" option.
#!/bin/bash
set -e
expect <<- DONE
spawn rsync --rsync-path="sudo\\ rsync" -uav myuser#example.com:/home/myuser/ /backups/home/myuser
expect ":"
send -- "mypassword\r"
expect eof
DONE
This does not work as intended. I get the following error message:
bash: sudo rsync: command not found
rsync: connection unexpectedly closed (0 bytes received so far) [Receiver]
rsync error: error in rsync protocol data stream (code 12) at io.c(226) [Receiver=3.1.1]
I have seen similar questions with respect to using spaces in a rsync command line, and have added single quotes, double quotes, and escape backslashes here and there, but nothing has worked yet.
How do I make "--rsync-path with spaces" work within an expect script?
The problem is that you've got this:
--rsync-path="sudo\\ rsync"
Inside Expect/Tcl, this is seen as:
--rsync-path="sudo rsync"
And, because Tcl's quoting rules are not the same as bash's, that then uses "sudo rsync" with the double quotes as the command to send to the remote side. Which confuses things terribly. The correct fix is to omit the double quotes; the (backslash-quoted) backslash will ensure that it all gets into spawn as one argument, and gets sent to the other side correctly.
I really don't like using HEREdocs with Tcl. Too many things can go weird when different sorts of quoting interact. It's much better to use a single script in the real target language, since then you can use variables to make things clearer:
#!/usr/bin/env expect
set remoteRsync "sudo rsync"
set from myuser#example.com:/home/myuser/
set to /backups/home/myuser
set pass "mypassword"
spawn rsync --rsync-path=$remoteRsync -uav $from $to
expect ":"
send -- "$pass\r"
expect eof
exit
This makes the structure of the code much simpler to see, and easier to debug. The bit with /usr/bin/env at the start is just a way to avoid having the bash wrapper.
And no, those variables won't need quoting at use. Tcl is not bash.
You can't use --rsync-path to do that, since what you want is word-splitting, i.e. something the shell does.
So how can you run a command that runs a command by specifying a single pathname?
On the remote system, write a script wrapper susync doing the sudo (don't forget to chmod 755):
#!/bin/sh
exec /path/to/sudo /path/to/rsync "$#"
and use
spawn rsync --rsync-path=/path/to/susync ...