file transfer using ssh sftpg3 - perl

I am writing a Perl script to do a secure file transfer using SSH sftpg3.exe
But I am having issue to accessing the source file.
the script able to pick the file from C:\xx\t.txt while running it from the directory
It is not showing error C:\Program is not a valid command.
my $sftpPath="C:\\Program Files\\client";
my $srcPath="C:\\xx\\test.txt";
my $trgCommand=$sftpPath." -D $srcPath user#host:/tmp/";
my $result=system("$trgCommand");
while running this script from C:\ directory it is running without error but I can not see the file in destination server.
Could you please help me sort out this file path issue ?
I want to run it from O:\ and it will pick the target file and sftpg3.exe from C:\ drive and do the file transfer (in ASCII mode) successfully.

try the below code
my $cmd="sftpg3.exe " . "$src_path user#host:";
system("C:\\Program Files\\Client\");
system($cmd);
Thanks.

You might have interpolation of #host in your third line because you are using double quotes (""). Do you have use strict and use warnings turned on? There might also be an issue with the space () in the path.
use strict;
use warnings;
use feature 'say';
my $sftp_path = q{"C:\Program Files\Client\sftpg3.exe"};
my $src_path = 'C:\xx\test.txt';
my $result = system( $sftp_path, '-D', $src_path, 'user#host:/tmp/' );
say $result;
Let's look at what I did.
When you tab-complete a path like C:\Program Files\foo in Windows cmd, it usually wraps them in double quotes if there is a space inside the path. So we use the q operator, which is equivalent to single quotes, and put double quotes inside. That also gives us the benefit that we don't have to escape the backslash \. Also see quote-like operators in perlop.
Same goes for the source path.
system allows you to pass all the arguments to the program you want to run as arguments to itself and will take care of the quoting
The double quote in "user#host:" will try to expand #host as an array. That doesn't work, because it's not defined. So there's a warning that you probably didn't see because you did not use strict and use warnings. Instead of the double quotes, use single quotes.
I used $sftp_path instead of $sftpPath because there is a convention in Perl to use underscores and no capital letters. We like camels, but not in our variable names. :)

Related

Perl SYSTEM command fails with "Bad file descriptor" when running via Jenkins

I have a simple system command to copy file from one folder to another:
my $cmd = "xcopy /Y c:\DBs\Support\db.bak c:\jenkins\workdir\sql-bak-files";
When I try to run the following system commands, all fails:
1. my $res = qx/$cmd/;
2. my $res = qx($cmd);
3. using back ticks
All tries returned the error: Error number -1, error message: "Bad file descriptor".
When trying to use system($cmd) the error was Error number 65280, error message: "No such file or directory".
This perl code is running via Jenkins (ver 2.190.1) and perl v5.26.0.
This problem started after migrating the code from mercurial to git, but I don't think it's related.
It worked before, but now always fail :(
A backslash has a special meaning in a Perl quoted string. It is used to escape the following character - to "turn off" any special meaning. If you want to use a backslash in a Perl quoted string, then you need to use another backslash to escape it.
my $cmd = 'xcopy /Y c:\\DBs\\Support\\db.bak c:\\jenkins\\workdir\\sql-bak-files';
Alternatively, Perl recognises forward slashes in Windows paths, so it might be easier to replace your code with this:
my $cmd = 'xcopy /Y c:/DBs/Support/db.bak c:/jenkins/workdir/sql-bak-files';
Note that in both cases I have replaced your double-quotes with single-quotes. This has no effect on your problem, but it seems strange to use double-quoted strings if you're not using any of their special characteristics (like the expansion of variables).
Update: To debug a problem like this, you can try printing the string.
$ perl -E'say "xcopy /Y c:\DBs\Support\db.bak c:\jenkins\workdir\sql-bak-files"'
xcopy /Y c:DBsSupportdb.bak c:jenkinsworkdirsql-bak-files

Folder name with space issue

How do I handle a folder name containing spaces in Perl? For example C:\Sample Picture\Data.
I wrote this
use File::Glob ':glob';
$indir = "C:\\Sample Picture\\Data\\";
#flist = bsd_glob( $indir.'*');
This is throwing an error
The syntax of the command is incorrect.
The error message The syntax of the command is incorrect comes from the Windows command line, not from Perl
The issue is not to do with File::Glob, but with whatever you are doing with the contents of #flist. It's my guess that you're using backticks or system to rename one or more of the files or directories. This will fail if you use paths that contain spaces without enclosing the complete path in double quotes
If you need any more help then you must show the relevant part of your code

tcl exec to open a program with agruments

I want to open a text file in notepad++ in a particular line number. If I do this in cmdline the command should be:
start notepad++ "F:\Path\test.txt" -n100
And it is working fine from command line. Now I have to do this from tcl. But I can't make this command work with exec. When I try to execute this:
exec "start notepad++ \"F:\Path\test.txt\" -n100"
I am getting this error:
couldn't execute "start notepad++ "F:\Path\test.txt" -n100": no such file or directory.
What am I missing. Please guide.
Similar to this question:
exec {*}[auto_execok start] notepad++ F:/Path/test.txt -n10
First, you need to supply each argument of the command as separate values, instead of a single string/list. Next, to mimic the start command, you would need to use {*}[auto_execok start].
I also used forward slashes instead of backslashes, since you would get a first level substitution and get F:Path est.txt.
EDIT: It escaped me that you could keep the backslashes if you used braces to prevent substitution:
exec {*}[auto_execok start] notepad++ {F:\Path\test.txt} -n10
You can simply surround the entire exec statement in curly braces. Like this:
catch {exec start notepad++.exe f:\Path\test.txt -n10}
I haven't found a perfect solution to this yet. All my execs seem to be different from each other. On windows there are various issues.
Preserving double quotes around filename (or other) arguments.
e.g. in tasklist /fi "pid eq 2060" /nh the quotes are required.
Preserving spaces in filename arguments.
Preserving backslash characters in filename arguments.
[Internally, Windows doesn't care whether pathnames have / or \, but some programs will parse the filename arguments and expect the backslash character].
The following will handle the backslashes and preserve spaces, but will not handle double-quoted arguments. This method is easy to use. You can build up the command line using list and lappend.
set cmd [list notepad]
set fn "C:\\test 1.txt"
lappend cmd $fn
exec {*}$cmd
Using a string variable rather than a list allows preservation of quoted arguments:
set cmd [auto_execok start]
append cmd " notepad"
append cmd " \"C:\\test 1.txt\""
exec {*}$cmd
Note that if you need to supply the full path to the command to be executed, it often needs to be quoted also due to spaces in the pathname:
set cmd "\"C:\\Program Files\\mystuff\\my stuff.exe\" "

How do we replace PATH in all the files with an env variable

I have around 230 files which are *.pl , *.txt and some are *.conf files which has a default path set to the current environment say /home/AD/USR/perl/5.8.0/bin/perl. I need to replace "/home/AD/USR" with an environment variable ${USR_PATH}. The files I want to modify are in subdirectories. Which means my script should find e.g find .|xargs grep -l "/home/AD/USR" all the files and then replace the string.
OLD: /home/AD/USR/perl/5.8.0/bin/perl
New : ${USR_PATH}/perl/5.8.0/bin/perl
Can some one give me a clue how do I do that?
Shell : /bin/bash
Env : Linux x86_64
If you replace part of a string with ${USR_PATH} you will refer to the perl variable $USR_PATH, not the environment variable, which is in perl referred to as $ENV{USR_PATH}.
perl -pi.bak -we 's#/home/AD/USR(?=/perl/5.8.0/bin/perl)#\$ENV{USR_PATH}#g'
*.pl *.txt *.conf
Using the lookahead will save you the trouble of replacing the rest of the path afterwards.
I assume you want to replace it with the literal value. If you want to replace it with the actual value in the environment variable, just remove the backslash in front of $ENV.
While using an environment variable seems handy and all, it will reduce your scripts portability. Why not use a configuration file? If you had done that from the start, you wouldn't be having this trouble. Search CPAN for a nice module.
perl -i -pe 's|/home/AD/USR/perl/5.8.0/bin/perl|\${USR_PATH}/perl/5.8.0/bin/perl|' <your files>

String replacement with Perl from inside a Makefile

I'm trying to replace a string, inside of a file, with perl from inside a Makefile.
InstallTo = $(PWD)/WebTest
BuildApache:
mkdir -p WebTest
cd Source/httpd; ./configure --prefix=$(InstallTo) --exec-prefix=$(InstallTo)
cd Source/httpd; make; make install
cd $(InstallTo)/conf; perl -pi -e 's/ServerRoot \"$(InstallTo)\"/ServerRoot/g' httpd.conf
cd $(InstallTo)/conf; cp -f httpd.conf httpd.conf.orig
I'm not sure exactly what I'm doing though, I've just tried to modify the perl line from something I found on the net. I think its the \" thats messing things up but I don't know enough about Perl to fix it.
You might want to try:
s|ServerRoot "$(InstallTo)"|ServerRoot|g
You're pasting a value with a slash in it as part of the search expression. It ends up as:
s/ServerRoot \"PWD/WebTest\"/ServerRoot/g
(Where PWD stands for any literal directory spec.) Since you can't escape the slash, that's always going to be a problem unless you use an alternative delimiter.
Since your variable contains '/' you need to use a different character for regular expressions, also you may want to use quotemeta or \Q..\E in regular expressions having variables which can contain special characters
s#\QServerRoot "$(InstallTo)"\E#ServerRoot#g
Refer to this post for more details how-do-i-handle-special-characters-in-a-perl-regex