concatenating/appending strings in TCL - string

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]

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.

Windows CMD expand filename if file has .double.extension

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%"

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

echo of var to file in SConscript

In an SConscript file I have a env variable BUILDID_STR
that contains a C string that I wish to output to a file.
bstr = env['BUILDID_STR']
print(bstr)
which when printed, print(bstr) correctly shows this:
//this file is automatically generated
static char* build_str="0|0.1.0|2014-05-29_16:16:51";
However, I can't get the var expanded/exported correctly, just the literal string is output instead of the above text:
cat src/log/src/version.c
env[BUILDID_STR]
Here's the pertinent part of my SConscript file
env.Command(target='#/src/log/src/version.c',
source=libSrcfiles,
action="echo env['BUILDID_STR'] > $TARGET")
env.SharedLibrary('log', [libSrcfiles, '#/src/log/src/version.c'])
I've also tried the code in a function and also passing to a shell script, all with the same result.
The reason I have .../version.c in the SharedLibrary is that my goal is to have the .c file generated only when on of the libSrcfiles is built, thereby version.c is compiled-in.
The "textfile" Tool offers two Builders Textfile() and Substfile() for cases like this. You probably want to use the first:
env = Environment(tools=['textfile'])
env['BUILDID_STR'] = 'A test'
env.Textfile('test.txt', ['$BUILDID_STR'])
As you have seen, the action is not expanding the env variable. In the action, you can refer to env variables with the $VAR syntax (just like referring to the $SOURCE and $TARGET variables provided by SCons):
env.Command(target='#/src/log/src/version.c',
source=libSrcfiles,
action="echo $BUILDID_STR > $TARGET")
This solution may not handle a BUILDID_STR containing multiple lines.
You may want to investigate a system that builds your source file from a template (instead of constructing the file contents entirely within a string). The Substfile Builder referenced in this previous question might be a good starting point -- you can provide a list of (key, value) pairs to be substituted in an input file. The Substfile Builder is built into recent versions of SCons.

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.

Resources