Powershell variable expansion when calling other programs - powershell

I have a small problem trying to unzip a file using the 7za
command-line utility in Powershell.
I set the $zip_source variable to the zip file's path and the
$unzip_destination to the desired output folder.
However the command-line usage of 7za needs arguments specified like this:
7za x -y <zip_file> -o<output_directory>
So my current call looks like this:
& '7za' x -y "$zip_source" -o$unzip_destination
Due to the fact that there can be no space between -o and the destination it
seems that PowerShell will not expand the $unzip_destination variable, whereas $zip_source is expanded.
Currently the program simply extracts all the files into the root of C:\ in
a folder named $unzip_destination.
Setting different types of quotes around the variable won't work neither:
-o"$unzip_destination" : still extracts to C:\$unzip_destination
-o'$unzip_destination' : still extracts to C:\$unzip_destination
-o $unzip_destination : Error: Incorrect command line
Is there any way to force an expansion before running the command?

Try this:
& '7za' x -y "$zip_source" "-o$unzip_destination"

try like this:
-o $($unzip_destination)
Editor's note: This solution only works with a space after -o (in which case just -o $unzip_destination would do) - if you remove it, the command doesn't work as intended.
This approach is therefore not suitable for appending a variable value directly to an option name, as required by the OP.

This should work:
& '7za' x -y $zip_source -o${unzip_destination}

Related

PowerShell command only works without spaces between arguments

I try certain source codes using PowerShell to extract an password protected archive using 7zip:
This command doesn' work (7zip is an alias for $7zipPath):
& 7zip x "$zipFile" -o "$output" -p $zipFilePassword
I get the this error:
Command Line Error:
Too short switch:
But when I remove the spaces between the variables -o and -p, the archive can be extracted. This behaviour confuses me with other command line tools like git etc.? Why is it so?
The behavior is specific to 7-Zip (7z.exe) and applies to whatever program (shell) you invoke it from:
Deviating from widely used conventions observed by CLIs such as git, 7z requires that even switches (options) that have mandatory arguments, such as -o and -p, have the argument directly attached to the switch name - no spaces are allowed:
& 7zip x $zipFile -o"$output" -p"$zipFilePassword"
Note that you normally need not enclose variable references in PowerShell in "..." (note how $zipFile isn't), even if they contain spaces. However, in order to attach them directly to switch names, you do.
Alternatively, you could enclose the entire token - switch name and argument - in double quotes:
& 7zip x $zipFile "-o$output" "-p$zipFilePassword"

7-zip extracted files not showing up when called from command line

I am attempting to write a command that calls 7-zip from the command line. My command is:
7z x z:\dev\archive.7z
Anytime I run this command in the command prompt, it acts like it's working, but when I navigate to the folder after the fact, the extracted files aren't there, although they are there if I run 7-zip from the contextual menu. Is there something I'm missing here?
If you don't specify a destination directory, 7z will extract files in your current directory.
As per the doc, to specify a target:
7z x archive.zip -oC:\path\to\target
Or use cd C:\path\to\target and then invoke your initial command.
In your case (from comments), what you want is:
7z x z:\dev\archive.7z -oz:\dev
This nice answer might help if you're confused with the options.
Try using the -spf switch
7z x z:\dev\archive.7z -spf

Current working directory for SXPG_COMMAND_EXECUTE?

Is there a way to specify the current working directory for the system command executed by the function module SXPG_COMMAND_EXECUTE?
I do not see any parameter which would allow me to do that either by defining the command in transaction SM69 or on the list of IMPORTING parameters in SE37.
It looks like by default such commands are started in DIR_HOME which can be viewed by the transaction AL11. Do I have any control over that?
There isn't a way of doing it via `SM69' unfortunately. I think the only solution is to create a script and call that.
I was going to suggest wrapping the statements in a SM69 command defined as a call to sh with parameters of -c 'cd <dir> && /path/to/command' but unfortunately that doesn't work. According to note 401095 wildcards are not permitted. When I tested, && was translated into a single &, causing the command to fail.
Would be good if you access this information using FM FILE_GET_NAME_USING_PATH (export the script name for which you want to find the physical directory).
The recieving path can be used in SXPG_COMMAND_EXECUTE.
Because the external commands I called were actually .bat files I solved this by putting the following expression at the beginning of each and every one.
cd /d %~dp0
This Stackoverflow question helped a lot actually.

Running a script in bash

I have a script in one of my application folders.Usually I just cd into that locatin in Unix box and run the script e.g.
UNIX> cd My\Folder\
My\Folder> MyScript
This prints the required result.
I am not sure how do I do this in Bash script.I have done the following
#!/bin/bash
mydir=My\Folder\
cd $mydir
echo $(pwd)
This basically puts me in the right folder to run the required script . But I am not sure how to run the script in the code?
If you can call MyScript (as opposed to ./MyScript), obviously the current directory (".") is part of your PATH. (Which, by the way, isn't a good idea.)
That means you can call MyScript in your script just like that:
#!/bin/bash
mydir=My/Folder/
cd $mydir
echo $(pwd)
MyScript
As I said, ./MyScript would be better (not as ambiguous). See Michael Wild's comment about directory separators.
Generally speaking, Bash considers everything that does not resolve to a builtin keyword (like if, while, do etc.) as a call to an executable or script (*) located somewhere in your PATH. It will check each directory in the PATH, in turn, for a so-named executable / script, and execute the first one it finds (which might or might not be the MyScript you are intending to run). That's why specifying that you mean the very MyScript in this directory (./) is the better choice.
(*): Unless, of course, there is a function of that name defined.
#!/bin/bash
mydir=My/Folder/
cd $mydir
echo $(pwd)
MyScript
I would rather put the name in quotes. This makes it easier to read and save against mistakes.
#!/bin/bash
mydir="My Folder"
cd "$mydir"
echo $(pwd)
./MyScript
Your nickname says it all ;-)
When a command is entered at the prompt that doesn't contain a /, Bash first checks whether it is a alias or a function. Then it checks whether it is a built-in command, and only then it starts searching on the PATH. This is a shell variable that contains a list of directories to search for commands. It appears that in your case . (i.e. the current directory) is in the PATH, which is generally considered to be a pretty bad idea.
If the command contains a /, no look-up in the PATH is performed. Instead an exact match is required. If starting with a / it is an absolute path, and the file must exist. Otherwise it is a relative path, and the file must exist relative to the current working directory.
So, you have two acceptable options:
Put your script in some directory that is on your PATH. Alternatively, add the directory containing the script to the PATH variable.
Use an absolute or relative path to invoke your script.

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>