Need module to accept the timestamp from command line - perl

I need a module to accept the following timestamp from command line in Perl.
2010/11/29 09:39:57
I have used the Getopt::Long module to accept the command line options. But it doesn't accept the full
timestamp from command line. It is accepting only date value(2010/11/29) not accepting the time value(09:39:57).
If anyone know the module to solve this issue, kindly let me know.
Thanks in advance.

Just put quotes around the timestamp. It should work fine with Getopt::Long
./script.pl -t '2010/11/29 09:39:57'

If you want them to be separate arguments, you could do something like this:
GetOptions('date=s{2}' => \#date);
my ($day, $time) = #date;

Related

Perl commandline arguments

I have a question about the commandline arguments in Perl. I'm not sure if someone has asked this question before because I'm not sure what to search for.
I'm having an aaplication where I pass some commandline arguments. But I want it to look like this: stepanalyzer --file=glasses.STEP --get=#62296,#3,#883
so I can say --get for example. And how I can pass multiple arguments with the --get
I hope someone is able to help me. Thanks in advance!
The library to use is Getopt::Long
As I said I needed something like --get="616","718"
So with this library you can put: GetOptions('file=s' => \$file, 'get=s' => \#ary);
'file=s'
Means: --file needs a string after it.
'get=s'
Means: The same, where now we can have multiple --get value on the command line and each such option adds its string to #ary. Thus the option as a comma-separated list, requested in the question, is one element in the array and one way to expand this is
#ary = split(/,/, join(',', #ary));
as shown in documentation
But there is also another way to give this: 'get=s#'. What you prefer.

Windows Powershell- Adding to a variable in a command call

I am new to Powershell and Stack Overflow, so sorry if this an obvious question. I have searched and searched and have not found any similar questions or answers. I am trying to call a command on Powershell and changing the file name by one. Here is the line giving me trouble:
fconv -rmsd ${line}_O[int]($modeO+1).mol2 --s=${line}_A$modeA.mol2
This program takes a line of code in the format
fconv -rmsd FILE_NAME.mol2 --s=FILE_NAME.mol2
and gives a result. My problem is adding 1 to $modeO. $modeO is a number that is pulled from a file and converted to an int by using
$modeO = file.txt | Select -Index 0
[int]$modeO = [convert]::ToInt32($ModeO.Trim(), 10)
Now, whenever I try this command it says "could not open 5157_O6+1.mol2" when modeO is 6. I want it to use the file O7, but the +1 is not adding properly. I have tried separating it with parentheses, curly braces, and putting [int] in front of ($modeO+1). Is there a way to add to a variable like this while using it? Any help is appreciated, thank you!

use a variable with whitespace Perl

I am currently working on a project but I have one big problem. I have some picture with a whitespace in the name and I want to do a montage. The problem is that I can't rename my picture and my code is like that :
$pic1 = qq(picture one.png);
$pic2 = qq(picture two.png);
my $cmd = "C:\...\montage.exe $pic1 $pic2 output.png";
system($cmd);
but because of the whitespace montage.exe doesn't work. How can I execute my code without renaming all my pictures?
Thanks a lot for your answer!
You can properly quote the filenames within the string you pass to system, as #Borodin shows in his answer. Something like: system("montage.exe '$pic1' '$pic2'")
However, A more reliable and safer solution is to pass the arguments to montage.exe as extra parameters in the system call:
system('montage.exe', $pic2, $pic2, 'output.png')
Now you don't have to worry about nesting the correct quotes, or worry about files with unexpected characters. Not only is this simpler code, but it avoids malicious injection issues, should those file names ever come from a tainted source. Someone could enter | rm *, but your system call will not remove all your files for you.
Further, in real life, you probably are not going to have a separate scalar variable for each file name. You'll have them in an array. This makes your system call even easier:
system('montage.exe', #filenames, 'output.png')
Not only is that super easy, but it avoids the pitfall of having a command line too long. If your filenames have nice long paths (maybe 50-100 characters), a Windows command line will exceed the max command length after around 100 files. Passing the arguments through system() instead of in one big string avoids that limitation.
Alternatively, you can pass the arguments to montage.exe as a list (instead of concatenating them all into a string):
use strict;
use warnings;
my $pic1 = qq(picture one.png);
my $pic2 = qq(picture two.png);
my #cmd = ("C:\...\montage.exe", $pic1, $pic2, "output.png");
system(#cmd);
You need to put quotes around the file names that have spaces. You also need to escape the backslashes
my $cmd = qq{C:\\...\\montage.exe "$pic1" "$pic2" output.png};
In unix systems, the best approach is the multi-argument form of system because 1) it avoids invoking a shell, and 2) that's the format accepted by the OS call. Neither of those are true in Windows. The OS call to spawn a program expects a command line, and system's attempt to form this command line is sometimes incorrect. The safest approach is to use Win32::ShellQuote.
use Win32::ShellQuote qw( quote_system );
system quote_system("C:\\...\\montage.exe", $pic1, $pic2, "output.png");

Passing a variable to a command in a script

I've been searching all over the place and since I'm taking my first steps in PERL this might be one of he dumbest questions but here it goes.
So I'm creating a script to manage my windows and later bind it to keyboard shortcuts, so I I'm trying to run a command and passing some variables:
my $command = `wmctrl -r :ACTIVE: -e 0,0,0,$monitors->{1}->{'width'}/2,$monitors->{1}->{'height'}`;
But I get an error saying I'm not passing the right parameters to the command, but if I do this, everything works great:
my $test = $monitors->{1}->{'width'}/2;
my $command = `wmctrl -r :ACTIVE: -e 0,0,0,$test,$monitors->{1}->{'height'}`;
So do I really have to do this? assign it first to a variable and then pass it, or there's a more elegant way of doing it?
The backticks operator (or the qx{}) accepts A string which is (possibly) interpolated. So accepts string and not expression like $var/2.
Thats mean than the $variables ($var->{1}->{some} too) are expanded but not the arithmetic expressions.
Therefore your 2 step variant works, but not the first.
If you want evaluate an expression inside the string you can use the next:
my $ans=42;
print "The #{[ $ans/2 ]} is only the half of answer\n";
prints
The 21 is only the half of answer
but it is not very readable, so better and elegant is what you're already doing - calculate the command argument in andvace, and to the qx{} or backticks only pass the calculated $variables.

zsh filename globbling/substitution

I am trying to create my first zsh completion script, in this case for the command netcfg.
Lame as it may sound I have stuck on the first hurdle, disclaimer, I know how to do this crudely, however I seek the "ZSH WAY" to do this.
I need to list the files in /etc/networking but only the files, not the directory component, so I do the following.
echo $(ls /etc/network.d/*(.))
/etc/network.d/ethernet-dhcp /etc/network.d/wireless-wpa-config
What I wanted was:
ethernet-dhcp wireless-wpa-config
So I try (excuse my naivity) :
echo ${(s/*\/)$(ls /etc/network.d/*(.))}
/etc/network.d/ethernet-dhcp /etc/network.d/wireless-wpa-config
It seems that this doesn't work, I'm sure there must be some clever way of doing this by splitting into an array and getting the last part but as I say, I'm complete noob at this.
Any advice gratefully received.
General note: There is no need to use ls to generate the filenames. You might as well use echo some*glob. But if you want to protect the possible embedded newline characters even that is a bad idea. The first example below globs directly into an array to protect embedded newlines. The second one uses printf to generate NUL terminated data to accomplish the same thing without using a variable.
It is easy to do if you are willing to use a variable:
typeset -a entries
entries=(/etc/network.d/*(.)) # generate the list
echo ${entries#/etc/network.d/} # strip the prefix from each one
You can also do it without a variable, but the extra stuff to isolate individual entries is a bit ugly:
# From the inside, to the outside:
# * glob the entries
# * NUL terminate them into a single string
# * split at NUL
# * strip the prefix from each one
echo ${${(0)"$(printf '%s\0' /etc/network.d/*(.))"}#/etc/network.d/}
Or, if you are going to use a subshell anyway (i.e. the command substitution in the previous example), just cd to the directory so it is not part of the glob expansion (plus, you do not have to repeat the directory name):
echo ${(0)"$(cd /etc/network.d && printf '%s\0' *(.))"}
Chris Johnsen's answer is full of useful information about zsh, however it doesn't mention the much simpler solution that works in this particular case:
echo /etc/network.d/*(:t)
This is using the t history modifier as a glob qualifier.
Thanks for your suggestions guys, having done yet more reading of ZSH and coming back to the problem a couple of days later, I think I've got a very terse solution which I would like to share for your benefit.
echo ${$(print /etc/network.d/*(.)):t}
I'm used to seeing basename(1) stripping off directory components; also, you can use echo /etc/network/* to get the file listing without running the external ls program. (Running external programs can slow down completion more than you'd like; I didn't find a zsh-builtin for basename, but that doesn't mean that there isn't one.)
Here's something I hope will help:
haig% for f in /etc/network/* ; do basename $f ; done
if-down.d
if-post-down.d
if-pre-up.d
if-up.d
interfaces