How to get shell expansion on scala sys.process invocations - scala

Consider a simple attempt at shell expansion:
Simple/direct approach :
scala> ("/bin/ls /tmp/*" run BasicIO(false, sb, None)).exitValue
ls: /tmp/*: No such file or directory
res18: Int = 1
I have tried a number of combinations of ProcessIO, BasicIO, Process, etc and can not figure out how to get shell expansion to work.
bash -c :
scala> ("bash -c \"/bin/ls /tmp/*\"" run BasicIO(false, sb, None)).exitValue
/tmp/*": -c: line 0: unexpected EOF while looking for matching `"'
/tmp/*": -c: line 1: syntax error: unexpected end of file
res19: Int = 2
Pipe to bash -s :
scala> ("echo \"/bin/ls /tmp/*\" | bash -s") run BasicIO(false, sb, None)).exitValue
<console>:1: error: ';' expected but ')' found.
("echo \"/bin/ls /tmp/*\" | bash -s") run BasicIO(false, sb, None)).exitValue
btw that last one in shell looks like the following (and works):
21:28:32/dstat $echo "/bin/ls /tmp/*" | bash -s
/tmp/OSL_PIPE_501_SingleOfficeIPC_a974a3af70d46eaeed927022833718b7
/tmp/oobelib.log
/tmp/spark-steve-org.apache.spark.deploy.master.Master-1.pid
/tmp/spark-steve-org.apache.spark.deploy.worker.Worker-1.pid
/tmp/KSOutOfProcessFetcher.501.qQkpPp2uZLdVc5pukHmfJMR4bkM=:
Shell escaping would also be of interest to understand wrt scala Process classes: an example including both expansion and escaping would be optimal.
UPDATE I found this JIRA - it may be relevant. I hope not - that means there were little/no hope for the functionality described here..
sys.process._ is so restrictive in what it can accept that is not usable https://issues.scala-lang.org/browse/SI-7027
Another update I found an old email thread involving the esteemed Daniel Sobral who mentions:
Because the quotes are not delimiting the parameter passed to bash --
it is Scala who decides how the arguments break up, and it simply
splits on spaces, without any quotation facility. If you try the
following, instead, it will work:
Seq("bash", "-c", "ls *.scala").!
It is looking ever more grim for a "fire and forget" version of running a shell command. I yearn for the ruby
%x{whatever shell string you want goes here}
e.g.
echo 'print %x{ls -lrtad /etc/* 2>&1}' | ruby
Which most satisfyingly returns:
-r--r--r-- 1 root wheel 69836 May 28 2013 /etc/php.ini.default-
5.2-previous~orig
lrwxr-xr-x 1 root wheel 30 Oct 22 2013 /etc/localtime -> /usr/share/zoneinfo/US/Pacific
-rw-r--r-- 1 root wheel 102 Nov 5 2013 /etc/hostconfig
-rw-r--r-- 1 root wheel 1286 Nov 5 2013 /etc/my.cnf
-rw-r--r-- 1 root wheel 4161 Dec 18 2013 /etc/sshd_config~previous
-rw-r--r-- 1 root wheel 199 Feb 7 2014 /etc/shells
-rw-r--r-- 1 root wheel 0 Sep 9 2014 /etc/xtab
-rw-r--r-- 1 root wheel 1316 Sep 9 2014 /etc/ttys
.. etc
but looks like that were not happening with Scala..

I fear you took my answer the wrong way. Ruby is doing the same thing, and I know this without looking at their code because what Java (and, by extension, Scala) presents as API is a direct translation of the Unix API.
It is shell that does shell expansions, and while it's perfectly possible for any other software to emulate them, it would be a losing game. Wildcards are often provided, but they are a small part of shell expansion.
My answer has everything you need, but let me expand on that:
import scala.sys.process._
implicit class RubyX(val sc: StringContext) extends AnyVal {
def x(args: Any*): ProcessBuilder = {
val strings = sc.parts.iterator
val expressions = args.iterator
var buf = new StringBuffer(strings.next)
while(strings.hasNext) {
buf append expressions.next
buf append strings.next
}
Process(Seq("bash", "-c", buf.toString))
}
}
then you can do
x"ls *.scala".!
I returned a ProcessBuilder, so you can pick whatever is the best form of execution for you, such as ! above that returns the exit code and echoes everything else to stdout.

Related

Magic method to assign variable in Ipython

Assign variable in bash script
$ d=$(date)
$ echo $d
Fri 18 Oct 2019 04:31:03 PM CST
However,when it come to ipython terminal,
In [25]: !d=$(date)
In [26]: !echo $d
In [27]:
What's the problem?
I'm not sure what you mean by "magic method".
If you want to run a bash command in your Jupyter/iPython notebook, you can use Python's subprocess module. In this case the following should work:
import subprocess
d = subprocess.Popen('date', stdout=subprocess.PIPE)
d = d.communicate()[0]
I think what you're looking for is this:
d=!date
d
or
d=!date
print(d)
it returns a list:
['lun 16 nov 2020 13:13:24 CET']
if you just want the string, try:
d[0]

Running Hive Using Scala As a Script

I was going through the processBuilder API of Scala, In order to run shell commands like we run in Shell Script, I could run few scripts but Having an issue with one type of Hive query execution.
When I run the below commands it was running success fully, but one type of format fails:
Running Shell Command(Successful):
scala> import sys.process._
scala> "ls -lrt /home/cloudera/Desktop".!
total 164
-rwxrwxr-x 1 cloudera cloudera 237 Apr 5 2016 Parcels.desktop
-rwxrwxr-x 1 cloudera cloudera 238 Apr 5 2016 Kerberos.desktop
-rwxrwxr-x 1 cloudera cloudera 259 Apr 5 2016 Express.desktop
Running Hive Query With File Option(Successful):
scala> "hive -f /home/cloudera/hi.hql" !!
warning: there was one feature warning; re-run with -feature for
details
ls: cannot access /usr/lib/spark/lib/spark-assembly-*.jar: No such
file or directory
2017-09-03 23:20:34,392 WARN [main] mapreduce.TableMapReduceUtil: The
hbase-prefix-tree module jar containing PrefixTreeCodec is not
present. Continuing without it.
Logging initialized using configuration in
file:/etc/hive/conf.dist/hive-log4j.properties
OK
Time taken: 0.913 seconds, Fetched: 2 row(s)
res20: String =
"100 Amit 12000 10
101 Allen 22000 20 .
"
Running Hive Query With -e Option(Failed):
If i had the run the below query on the terminal I could run in the below given Format.
bash$ hive -e "select * staging.from employee_canada;"
The problem while running the same query in scala terminal fails because of the double quotes ("") # the Select query. How can I escape those and run successfully. Tried using triple quotes and as well as escape "\" sequence but still failed to execute.
scala> "hive -e select * staging.from employee_canada; "!!
Below is the Error:
FAILED: ParseException line 1:6 cannot recognize input near '<EOF>'
'<EOF>' '<EOF>' in select clause
java.lang.RuntimeException: Nonzero exit value: 64
at scala.sys.package$.error(package.scala:27)
at scala.sys.process.ProcessBuilderImpl$AbstractBuilder.slurp
at scala.sys.process.ProcessBuilderImpl$AbstractBuilder.$bang$bang(
ProcessBuilderImpl.scala:102)
... 32 elided

erlang os:cmd() command with UTF8 binary

I'm trying to get an Erlang function to execute a bash command containing unicode characters. For example, I want to execute the equivalent of:
touch /home/jani/ჟანიweł
I put that command in variable D, for example:
io:fwrite("~ts", [list_to_binary(D)]).
touch /home/jani/ჟანიwełok
but after I execute:
os:cmd(D)
I get file called á??á??á??á??weÅ?. How can I fix it?
os:cmd(binary_to_list(unicode:characters_to_binary("touch /home/jani/编程"))).
Executing this command creates a file named ��, while executing the equivalent touch command directly in a terminal creates the file with the correct name.
Its because Erlang reads your source files like latin1 by default, but on newer versions of erlang you can set your files to use unicode.
%% coding: utf-8
-module(test).
-compile(export_all).
test() ->
COMMAND = "touch ჟანიweł",
os:cmd(COMMAND).
and then compiling and executing the module works fine
rorra-air:~ > erl
Erlang/OTP 17 [erts-6.4] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
Eshell V6.4 (abort with ^G)
1> c(test).
{ok,test}
2> test:test().
[]
and it created the file on my filesystem
rorra-air:~ > ls -lta
total 144
-rw-r--r-- 1 rorra staff 0 Jun 9 15:18 ჟანიweł

Perl: strange behaviour of glob with files greater than 2 GB

I'm simply trying to get a list of filenames given a path with wildcard.
my $path = "/foo/bar/*/*.txt";
my #file_list = glob($path);
foreach $current_file (#file_list) {
print "\n- $current_file";
}
Mostly this works perfectly, but if there's a file greater than 2GB, somewhere in one of the /foo/bar/* subpaths, the glob returns an empty array without any error or warning.
If I remove the file file or add a character/bracket sequence like this:
my $path = "/foo/bar/*[0-9]/*.txt";
or
my $path = "/foo/bar/*1/*.txt";
then the glob works again.
UPDATE:
Here's an example (for a matter of business policy I had to mask the pathname):
[root]/foo/bar # ls -lrt
drwxr-xr-x 2 root system 256 Oct 11 2006 lost+found
drwxr-xr-x 2 root system 256 Dec 27 2007 abc***
drwxr-xr-x 2 root system 256 Nov 12 15:32 cde***
-rw-r--r-- 1 root system 2734193149 Nov 15 05:07 archive1.tar.gz
-rw-r--r-- 1 root system 6913743 Nov 16 05:05 archive2.tar.gz
drwxr-xr-x 2 root system 256 Nov 16 10:00 fgh***
[root]/foo/bar # /home/user/test.pl
[root]/foo/bar #
Removing the >2GB file (or globbing with "/foo/bar/[acf]/" istead of "/foo/bar//")
[root]/foo/bar # ls -lrt
drwxr-xr-x 2 root system 256 Oct 11 2006 lost+found
drwxr-xr-x 2 root system 256 Dec 27 2007 abc***
drwxr-xr-x 2 root system 256 Nov 12 15:32 cde***
-rw-r--r-- 1 root system 6913743 Nov 16 05:05 archive2.tar.gz
drwxr-xr-x 2 root system 256 Nov 16 10:00 fgh***
[root]/foo/bar # /home/user/test.pl
- /foo/bar/abc***/heapdump.phd.gz
- /foo/bar/cde***/javacore.txt.gz
- /foo/bar/fgh***/stuff.txt
[root]/foo/bar #
Any suggestion?
I'm working with:
Perl 5.8.8
Aix 5.3
The filesystem is a local jfs.
In the absence of a proper answer you're going to want a work-around. I'm guessing you've hit some platform-specific bug in the glob() implementation of 5.8.8
I had a quick look at the source on CPAN but my C is too rusty to spot anything useful.
There have been lots of changes to that module though, so a bug may well have been reported and fixed. You're not even on the last release of 5.8 - there's a 5.8.9 out there which mentions updates to AIX compatibility and File::Glob.
I'd test this by installing local::lib if you haven't already and then perhaps cpanm and try updating File::Glob - see what that does. You might need to download the files by hand from e.g. here
If that solves the problem then you can either deploy updates to the required systems, or you'll have to re-implement the bits of glob() you want. Which is going to depend on how complex your patterns get.
If it doesn't solve the problem then at least you'll be able to stick some printf's into the code and see what it's doing.
Hopefully someone will post a real answer and make this redundant about 5 minutes after I click "Post Your Answer" though.
I've never used the new Glob function before, so i cant comment on benefits/problems, but it seems quite a lot of people have had issues using it: see => https://stackoverflow.com/search?q=perl+glob&submit=search for some questions and possible solutions.
IF you don't mind trying out something else:
Here is my tried and tested 'old school' perl solution i have used in countless projects:
my $path = "/foo/bar/";
my #result_array = qx(find $path -iname '*.txt'); #run the system find command
If you - for whatever reason prefer not to run a system command from within your script, then lookup the built in Find::Perl Module instead: http://search.cpan.org/~dom/perl-5.12.5/lib/File/Find.pm
good luck

Can't get launchd to work at Startup/Shutdown on OS X Lion

I followed some online guides trying to get some headless VMs to start/suspend automatically at boot/shutdown on my Mac. I can't get it to work at all. This is my first time trying to get script runs on Startup/Shutdown, so it could be that I'm just missing something very basic and if that's the case I apologize.
These are the steps I followed:
Created a directory /Library/StartupItems/HeadlessVM
Created two files within that directory:
-rwxr--r-- 1 root wheel 242 Feb 19 19:05 HeadlessVM
-rw-r--r-- 1 root wheel 188 Feb 20 12:42 StartupParameters.plist
Contents for HeadlessVM
$ cat HeadlessVM
#!/bin/sh
. /etc/rc.common
StartService ()
{
ConsoleMessage "Starting HeadlessVM"
/usr/local/bin/runvmheadless
}
StopService ()
{
ConsoleMessage "Suspending HeadlessVM"
/usr/local/bin/suspendvmheadless
}
RunService "$1"
Contents for StartupParameters.plist
$ cat StartupParameters.plist
{
Description = "Runs/Suspends Virtual Machine Headless on OS X Startup/Shutdown";
Provides = ("HeadlessVM");
Uses = ("Disks");
OrderPreference = ("Late");
}
Created my script files, that will perform both actions:
-rwxr-xr-x# 1 xxxxxxx admin 164 Feb 19 01:06 runvmheadless
-rwxr-xr-x# 1 xxxxxxx admin 160 Feb 19 01:19 suspendvmheadless
Contents for runvmheadless
$ cat runvmheadless
#!/bin/bash
"/Applications/VMware Fusion.app/Contents/Library/vmrun" -T fusion start "/Volumes/Archive/Virtual Machines/vm.vmwarevm/vm.vmx" nogui
Contents for suspendvmheadless
$ cat suspendvmheadless
#!/bin/bash
"/Applications/VMware Fusion.app/Contents/Library/vmrun" -T fusion suspend "/Volumes/StaticData/Virtual Machines/vm.vmwarevm/vm.vmx"
My troubleshooting so far:
If I run the scripts from the terminal, they work as intended.
If I run sudo /sbin/SystemStarter (start or stop) "HeadlessVM" it also works.
On console I only see the following when I reboot, no clue on what's wrong tho.
2/20/12 12:11:09.128 PM SystemStarter: Runs/Suspends Virtual Machine Headless on OS X Startup/Shutdown (100) did not complete successfully
Appreciate any help, Thank you.
I found what was wrong. The code above is fine, the problem is that my scripts are trying to get data from an encrypted secondary disk which was not available at boot time.
I used this in order to bypass this problem:https://github.com/jridgewell/Unlock
Thanks