Windows CMD expand filename if file has .double.extension - string

I'm writing a script that converts a Markdown file to a PDF, facilitated by Pandoc.
So if you drag C:\Users\User\Documents\English\PAPER1.md onto the script, it'll create C:\Users\User\Documents\English\PDFs\PAPER1.pdf.
This is achieved in the header of the script via
set INPUT=%1
set PDFDIR=%~dp1\PDFs
set PDF=%PDFDIR%\%~n1.pdf
However, in certain circumstances, the input filename will be Something.md.txt, in which case I only still want to output Something.pdf. (Removing more than three extensions will probably not be necessary or desirable.)
But the current setup only strips one extension, producing Something.md.pdf.
However, %~nn1.pdf does not work, nor does set p=%~n1 set PDF=%~np, giving
The following usage of the path operator in batch-parameter
substitution is invalid: %~np
How do I get the bare filename of a file with "two extensions"?

I'd change every line from the provided header of the script to:
Set "INPUT=%~1"
Set "PDFDIR=%~dp1PDFs"
For %%A In ("%~dpn1") Do Set "PDF=%PDFDIR%\%%~nA.pdf"
Because there's no surety of the input content, please use best practice and always reference these variables wherever possible using doublequotes:
Echo "%INPUT%"
Echo "%PDFDIR%"
Echo "%PDF%"

Related

Check if same file exists in another directory using Bash

I'm new to bash and would like your help; couldn't find an answer for this case.
I'm trying to check if the files in one directory exist in another directory
Let's say I have the path /home/public/folder/ (here I have several files)
and I want to check if the files exist in /home/private/folder2
I tried that
for file in $firstPath/*
do
if [ -f $file ]; then
(ask if to over write etc.. rest of the code)
And also
for file in $firstPath/*
do
if [ -f $file/$secondPath ]; then
(ask if to over write etc.. rest of the code)
Both don't work; it seems that in the first case, it compares the files in the first path (so it always ask me if I want to overwrite although it doesn't exist in the second path)
And in the second case, it doesn't go inside the if statement.
How could I fix that?
When you have a construct like for file in $firstPath/*, the value of $file is going to include the value of $firstPath, which does not exist within $secondPath. You need to strip the path in order to get the bare filename.
In traditional POSIX shell, the canonical way to do this was with an external tool called basename. You can, however, achieve what is generally thought to be equivalent functionality using Parameter Expansion, thus:
for file in "$firstPath"/*; do
if [[ -f "$secondPath/${file##*/}" ]]; then
# file exists, do something
fi
done
The ${file##*/} bit is the important part here. Per the documentation linked above, this means "the $file variable, with everything up to the last / stripped out." The result should be the same as what basename produces.
As a general rule, you should quote your variables in bash. In addition, consider using [[ instead of [ unless you're actually writing POSIX shell scripts which need to be portable. You'll have a more extensive set of tests available to you, and more predictable handling of variables. There are other differences too.

concatenating/appending strings in TCL

I am trying to append a file name to a project directory in TCL:
set filename hello
set currentPath "D:/TEMP/project name/subfolder/"
puts [append $currentPath $filename]
According to the docs all that is needed is a varName to which we are appending and a ?value which is getting appended to varName. Unfortunately when I run the above code I only get hello as output. How can I perform this simple task on TCL?
The problem is that you're using the variable value where you need the variable name. In Tcl (as opposed to some other languages), the $ means “read this variable now” and that's meaning that you're giving a rather odd variable name to append. Try switching from:
puts [append $currentPath $filename]
to:
puts [append currentPath $filename]
# Be aware that this *updates* the currentPath variable
Also, if you're using this to make a filename, do consider using file join instead; it handles all sorts of tricky cases you're not currently aware of so that you don't ever need to become aware of them.
puts [file join $currentPath $filename]

Batch Script - Comma causing problems when writing numerical value to txt file

So this is an example of a script I'm writing to produce txt file containing a list of correctly formatted commands to be passed to another system, based on a long series of questions.
If objectName, objectNumber, or objectCategory are assigned an alphanumeric value, the script will write correctly to the txt file. However, if I were to assign a numerical value, the value is not written to the txt file.
I'm guessing this is a syntax issue related to the use of a comma, as I can replace it with with pretty much anything and the script will behave, though unfortunately it has to be a comma.
#ECHO OFF
SET objectCounter=1
SET /p objectName=What is the name of the object %objectCounter%?:
#ECHO OBJECTNAME%objectCounter%,%objectName%> objects.txt
SET /p objectNumber=How many of object %objectCounter% are there?:
#ECHO OBJECTNUMBER%objectCounter%,%objectNumber%>> objects.txt
SET /p objectCategory=Which group does object %objectCounter% belong to?:
#ECHO OBJECTCATEGORY%objectCounter%,%objectNumber%>> objects.txt
This is an example of the output to the txt file if objectNumber is assigned a value of 1:
OBJECTNAME1,Apple
OBJECTNUMBER1,
OBJECTCATEGORY1,Fruit
And this is an example of the output to the txt file if objectNumber is assigned a value of 2 or more:
OBJECTNAME1,Apple
OBJECTCATEGORY1,Fruit
This is a simplification: a echo command to send the text data 1 to a file:
echo data 1>somewhere.txt
Here it is easy to see that the 1 will be handled by the parser as the stream number to redirect, not data to send to the file.
But the question is not using a space, but a comma. Why the same behaviour? Because from the parser point of view, spaces, tabs, commas, semicolons, parenthesis and equals are delimiters. All these lines fail the same way (tabs omited)
echo data 1>>somewhere.txt
echo data,1>>somewhere.txt
echo data;1>>somewhere.txt
echo data=1>>somewhere.txt
echo data(1>>somewhere.txt
echo data)1>>somewhere.txt
How to handle it? It is necessary to separate the digit from the redirection, so we can change the order in the line
>somewhere.txt echo data,1
or force the parser see the separation
(echo data,1)>somewhere.txt
or, if the data is inside a variable, we can also use delayed expansion
set "n=1"
setlocal enabledelayedexpansion
echo data,!n!>somewhere.txt
Of course, we can also do
echo data,1 >>somewhere.txt
including a space between the data and the redirection, but the space will be included in the redirected data.
Another option is to reorganize the code
#ECHO OFF
SET objectCounter=1
SET /p "objectName=What is the name of the object %objectCounter%?: "
SET /p "objectNumber=How many of object %objectCounter% are there?: "
SET /p "objectCategory=Which group does object %objectCounter% belong to?: "
> objects.txt (
ECHO OBJECTNAME%objectCounter%,%objectName%
ECHO OBJECTNUMBER%objectCounter%,%objectNumber%
ECHO OBJECTCATEGORY%objectCounter%,%objectCategory%
)
It looks like it has to do with output redirection in conjunction with the comma. I think, with the comma in there, the numeric value is being bound to the redirection rather than to the thing being output.
In other words, while:
set x=1
echo xyzzy%x%>qq.txt
will work (the thing being output is xyzzy%x% with a redirection of >qq.txt), the following will not:
set x=1
echo xyzzy,%x%>qq.txt
(presumably because the thing being output is xyzzy, with a redirection operation 1>qq.txt which is the same as >qq.txt). That also explains the difference you're seeing between 1 and other numbers since 1 is standard output.
You can see a similar problem even without variable expansion:
C:\pax> echo xyzzy1>qq.txt
C:\pax> type qq.txt
xyzzy1
C:\pax> echo xyzzy,1>qq.txt
C:\pax> type qq.txt
xyzzy,
One way around it is to reorganise your components so that the numeric value cannot be tied to the redirection:
>>objects.txt ECHO OBJECTNUMBER%objectCounter%,%objectNumber%
I tend to prefer putting them at the start since using something like:
echo xyzzy >file
will actually output xyzzy and the space immediately before the >.
Modifying the lines like that (and fixing your third echo so it outputs the category rather than the number again) gives you:
What is the name of the object 1?: Apple
How many of object 1 are there?: 1
Which group does object 1 belong to?: Fruit
with the resultant file being:
OBJECTNAME1,Apple
OBJECTNUMBER1,1
OBJECTCATEGORY1,Fruit

Extracting string after last instance of delimiter in a Batch file

I'm working on writing a Windows batch file that is called by a Java program. A number of different strings denoting file directories are passed into the batch file as parameters. I am trying to figure out how to extract a string after the last instance of the "\". For example, I have three directories:
C:\Users\owner\Documents
C:\Users\owner\Videos
C:\Users\owner\Pictures\Trip
I would like to split it so that the strings become:
Documents
Videos
Trip
How would you guys suggest I do this?
EDIT: A follow-up question has been asked here: For loop in Windows batch file: Error: "The syntax of the command is incorrect"
After assigned one parameter to "param" variable, use:
for %%a in (%param:\= %) do set lastDir=%%a
This method works as long as the last directory does NOT have spaces. This detail may be fixed, if needed. The processing of all parameters would be like this:
:nextParam
set "param=%~1"
if not defined param goto endParams
for %%a in (%param:\= %) do set lastDir=%%a
echo Last dir: %lastDir%
shift
goto nextParam
:endParams
Or, in a simpler way (with no spaces restrictions):
:nextParam
if "%~1" equ "" goto endParams
echo Last dir: %~N1
shift
goto nextParam
:endParams
If the strings are passed as arguments 1-3. you can use %~n1, %~n2, %~n3 to get the last folder in the path.

Passing data into perl script from command line

I have a perl script the creates a report based on an xml definition. Currently these definitions all exist as .xml files.
So I have the script run-report.pl, which can take a path to a definition file and create the report.
Now I want to create run-reports-from-db.pl, which will generate the report definition based on same database entries. I don't want to create temp files to pass to run-report.pl, I would just like to pass in the definition somehow.
So instead of saying:
run-report.pl -def=./path/to/def.xml
I want to be able to say:
run-report.pl --stream
And have the report definition available in <STDIN>
I am sure there is pretty trivial way to do this???
If I understand your question correctly, all you need is one | (pipe).
./generate-xml-from-db.pl | ./run-report.pl --stream
Anything the first process in the pipeline prints to stdout will appear in the second process's stdin.
As long as you read from STDIN, you have it available. Notice what happens with you take the code below name it something like echo.pl run it at the command line and paste reams of text.
#!/usr/bin/perl -w
use 5.010;
use strict;
use warnings;
while ( <> ) {
say;
}
<> is the Perl shorthand for "read from STDIN".
As long as the method you're using to launch the process has a way to get a hold of the standard input and outputs, you can just write it to that handle. You have to use the ways that are available to you. In Java, for example, you'd have to get the input stream of the process, in a batch command you have to pipe it. At a GUI terminal you can cut and paste.

Resources