Bash - Date command and space - linux

I am trying to create a script that uses the date command in bash. I am familiar with the basic syntax of the date command.
Here is the simple script:
#!/bin/bash
set -x
DATE_COMMAND="date "+%y-%m-%d %H:%M:%S""
echo "$($DATE_COMMAND)"
set +x
The thing is that the above code doesn't work.
Here is the output:
+ DATE_COMMAND='date +%y-%m-%d'
+ %H:%M:%S
onlyDate: line 3: fg: no job control
+ echo ''
+ set +x
Ok, so the problem is that the bash splits the command because of the space. I can understand that but I don't know how to avoid that. I have tried to avoid the space with \, to avoid the space and the ". Also the single quotes doesn't seem to work.
Please note that I know that this script can be written this way:
#!/bin/bash
set -x
DATE_COMMAND=$(date "+%y-%m-%d %H:%M:%S")
echo "$DATE_COMMAND"
set +x
I have tried that but I can't use this approach because I want to run the command several times in my script.
Any help will be really appreciated!

The correct approach is to define your own function inside your Bash script.
function my_date {
date "+%y-%m-%d %H:%M:%S"
}
Now you can use my_date as if it were an external program.
For example:
echo "It is now $(my_date)."
Or simply:
my_date
Why isn't your approach working?
The first problem is that your assignment is broken.
DATE_COMMAND="date "+%y-%m-%d %H:%M:%S""
This is parsed as an assignment of the string date +%y-%m-%d to the variable DATE_COMMAND. After the blank, the shell starts interpreting the remaining symbols in ways you did not intend.
This could be partially fixed by changing the quotation.
DATE_COMMAND="date '+%y-%m-%d %H:%M:%S'"
However, this doesn't really solve the problem because if we now use
echo $($DATE_COMMAND)
It will not expand the argument correctly. The date program will see the arguments '+%y-%m-%d and %H:%M:%S' (with quotes) instead of a single string. This could be solved by using eval as in
DATE_COMMAND="date '+%y-%m-%d %H:%M:%S'"
echo $(eval $DATE_COMMAND)
where the variable DATE_COMMAND is first expanded to the string date '+%y-%m-%d %H:%M:%S' that is then evaluated as if it were written like so thus invoking date correctly.
Note that I'm only showing this to explain the issue. eval is not a good solution here. Use a function instead.
PS It is better to avoid all-uppercase identifier strings as those are often in conflict with environment variables or even have a magic meaning to the shell.

Escaping the space works for me.
echo `date +%d.%m.%Y\ %R.%S.%3N`

For long scripts
declare variables section:
dateformat="%Y-%m-%d %H:%M:%S"
anywhere to get date:
datestr=`date +"${dateformat}"`
anywhere to echo date:
echo ${datestr}
For short simple scripts DaniëlGu's answer is the best:
echo `date +%d.%m.%Y\ %R.%S.%3N`

Shortest answer is
#if you want to store in a variable
now=$(date '+%F" "%T');
echo $now
#or direct output
date '+%F" "%T'

I'm using:
DF="+%m/%d/%Y %H:%M:%S";
FILE_DATE=$(date "${DF[#]}" -r "${SCHEMA_LOCAL_PATH}.gz");
Seems Bash treats space in $DF as an array's separator and 'date' receives 2 agruments instead of one so I'm sending an array.
Also works for me (check "+" sign):
DF="%m/%d/%Y %H:%M:%S";
FILE_DATE=$(date +"${DF}" -r "${SCHEMA_LOCAL_PATH}.gz");

Related

linux bash, passing paramenters using a varible issue

I am trying to use a variable to store the parameters, here is the simple test:
#!/bin/bash
sed_args="-e \"s/aaaa/bbbb/g\""
echo $sed_args`
I expected the output to be
-e "s/aaaa/bbbb/g"
but it gives:
"s/aaaa/bbbb/g"
without the "-e"
I am new to bash, any comment is welcome. Thanks, maybe this is already answered somewhere.
You need an array to construct arguments dynamically:
#!/usr/bin/env bash
sed_args=('-e' 's/aaaa/bbbb/g')
echo "${sed_args[#]}"
When you use the variable without double quotes, it gets word split by the shell even before echo sees the value(s). Then, the bash's builtin echo interprets -e as a parameter for itself (which is normally used to turn on interpretation of backslash escapes).
When you double quote the variable, it won't be split and will be interpreted as a single argument to echo:
echo "$sed_args"
For strings you don't control, it's safer to use printf as it doesn't take any arguments after the format string:
printf %s "$string"

Writing variables to file with bash

I'm trying to configure a file with a bash script. And the variables in the bash script are not written in file as it is written in script.
Ex:
#!/bin/bash
printf "%s" "template("$DATE\t$HOST\t$PRIORITY\t$MSG\n")" >> /file.txt
exit 0
This results to template('tttn') instead of template("$DATE\t$HOST\t$PRIORITY\t$MSG\n in file.
How do I write in the script so that the result is template("$DATE\t$HOST\t$PRIORITY\t$MSG\n in the configured file?
Is it possible to write variable as it looks in script to file?
Enclose the strings you want to write within single quotes to avoid variable replacement.
> FOO=bar
> echo "$FOO"
bar
> echo '$FOO'
$FOO
>
Using printf in any shell script is uncommon, just use echo with the -e option.
It allows you to use ANSI C metacharacters, like \t or \n. The \n at the end however isn't necessary, as echo will add one itself.
echo -e "template(${DATE}\t${HOST}\t${PRIORITY}\t${MSG})" >> file.txt
The problem with what you've written is, that ANSI C metacharacters, like \t can only be used in the first parameter to printf.
So it would have to be something like:
printf 'template(%s\t%s\t%s\t%s)\n' ${DATE} ${HOST} ${PRIORITY} ${MSG} >> file.txt
But I hope we both agree, that this is very hard on the eyes.
There are several escaping issues and the power of printf has not been used, try
printf 'template(%s\t%s\t%s\t%s)\n' "${DATE}" "${HOST}" "${PRIORITY}" "${MSG}" >> file.txt
Reasons for this separate answer:
The accepted answer does not fit the title of the question (see comment).
The post with the right answer
contains wrong claims about echo vs printf as of this post and
is not robust against whitespace in the values.
The edit queue is full at the moment.

bash prevent escaping with echo

I am relatively new to linux and am trying to create a TikZ figure parsing a file. In order to do so I read in the file with a $%&-bash script containing the following statement
echo "\fill[color=blue] ($xp,$zp) circle (5pt);" >> $fout
this results in the following output
^Lill[color=blue] ($xp,$zp) circle (5pt);
Obviously echo escapes the \f and I did not find a way around it.
I have tried all options like "-e" "-n" and what have you, have tried all kinds of combinations of " ' etc, but to no avail.
I am stuck as so often with linux, but this time even google didn't help (OMG=Oh My Google!!!!!!!!).
echo should not do backslash escapes by default, unless -e is specified. You can try echo -E to force turning them off (in case you have aliased echo to echo -e or something).
Alternatively, try using single quotes (although now that I think about it, I don't see how it would help):
echo '\fill[color=blue] ('"$xp,$zp"') circle (5pt);' >> $fout

How to pass local shell script variable to expect?

My question is related to How to pass variables from a shell script to an expect script?
but its slightly different:
Apart from passing two runtime shell script variables, I want to pass a variable thats inside the shell script For eg:
#!/bin/sh
d=`date '+%Y%m%d_%H%M'`
expect -c '
expect "sftp>"
#use $d here(how?)
'
You don't need to pass a date variable into expect. It has a very good date command builtin:
expect -c '
# ...
set d [timestamp -format "%Y%m%d_%H%M"]
something_with $d
# ...
'
If you need to do more complicated date manipulation, read about the Tcl clock command
Another good technique to pass shell variables to expect (without having to do complicated/messy quoting/escaping) is to use the environment: export your shell variables, and then access them with expect's global env array:
export d=$(date ...)
expect -c 'puts "the date is $env(d)"'
This seems the wrong way to do things. You should set up SSH keys (with ssh-keygen and ssh-copy-id), google about this.
Anyway, try this :
#!/bin/sh
d=`date '+%Y%m%d_%H%M'`
expect -c "
something_with $d"
Note the double quotes instead of single quotes.
"Double quote" every literal that contains spaces/metacharacters and every expansion: "$var", "$(command "$var")", "${array[#]}", "a & b". Use 'single quotes' for code or literal $'s: 'Costs $5 US', ssh host 'echo "$HOSTNAME"'. See http://mywiki.wooledge.org/Quotes , http://mywiki.wooledge.org/Arguments and http://wiki.bash-hackers.org/syntax/words

Append date to filename in linux

I want add the date next to a filename ("somefile.txt"). For example: somefile_25-11-2009.txt or somefile_25Nov2009.txt or anything to that effect
Maybe a script will do or some command in the terminal window. I'm using Linux(Ubuntu).
The script or command should update the filename to a new date everytime you want to save the file into a specific folder but still keeping the previous files. So there would be files like this in the folder eventually: filename_18Oct2009.txt , filename_9Nov2009.txt , filename_23Nov2009.txt
Info/Summary
With bash scripting you can enclose commands in back ticks or parantheses. This works great for labling files, the following wil create a file name with the date appended to it.
Methods
Backticks -
$ echo myfilename-"`date +"%d-%m-%Y"`"
$(parantheses) - :
$ echo myfilename-$(date +"%d-%m-%Y")
Example Usage:
echo "Hello World" > "/tmp/hello-$(date +"%d-%m-%Y").txt"
(creates text file '/tmp/hello-28-09-2022.txt' with text inside of it)
Note, in Linux quotes are your friend, best practice to enclose the file name to prevent issues with spaces and such in variables.
There's two problems here.
1. Get the date as a string
This is pretty easy. Just use the date command with the + option. We can use backticks to capture the value in a variable.
$ DATE=`date +%d-%m-%y`
You can change the date format by using different % options as detailed on the date man page.
2. Split a file into name and extension.
This is a bit trickier. If we think they'll be only one . in the filename we can use cut with . as the delimiter.
$ NAME=`echo $FILE | cut -d. -f1
$ EXT=`echo $FILE | cut -d. -f2`
However, this won't work with multiple . in the file name. If we're using bash - which you probably are - we can use some bash magic that allows us to match patterns when we do variable expansion:
$ NAME=${FILE%.*}
$ EXT=${FILE#*.}
Putting them together we get:
$ FILE=somefile.txt
$ NAME=${FILE%.*}
$ EXT=${FILE#*.}
$ DATE=`date +%d-%m-%y`
$ NEWFILE=${NAME}_${DATE}.${EXT}
$ echo $NEWFILE
somefile_25-11-09.txt
And if we're less worried about readability we do all the work on one line (with a different date format):
$ FILE=somefile.txt
$ FILE=${FILE%.*}_`date +%d%b%y`.${FILE#*.}
$ echo $FILE
somefile_25Nov09.txt
cp somefile somefile_`date +%d%b%Y`
You can add date next to a filename invoking date command in subshell.
date command with required formatting options invoked the braces of $() or between the backticks (`…`) is executed in a subshell and the output is then placed in the original command.
The $(...) is more preferred since in can be nested. So you can use command substitution inside another substitution.
Solutions for requests in questions
$ echo somefile_$(date +%d-%m-%Y).txt
somefile_28-10-2021.txt
$ echo somefile_$(date +%d%b%Y).txt
somefile_28Oct2021.txt
The date command comes with many formatting options that allow you to customize the date output according to the requirement.
%D – Display date in the format mm/dd/yy (e.g. : 10/28/21)
%Y – Year (e.g. : 2021)
%m – Month (e.g. : 10)
%B – Month name in the full string format (e.g. : October)
%b – Month name in the shortened string format (e.g. : Oct)
%d – Day of month (e.g. : 28)
%j – Day of year (e.g. : 301)
%u – Day of the week (e.g. : 4)
%A – Weekday in full string format (e.g. : Thursday)
%a – Weekday in shortened format (e.g. : Thu)
I use this script in bash:
#!/bin/bash
now=$(date +"%b%d-%Y-%H%M%S")
FILE="$1"
name="${FILE%.*}"
ext="${FILE##*.}"
cp -v $FILE $name-$now.$ext
This script copies filename.ext to filename-date.ext, there is another that moves filename.ext to filename-date.ext, you can download them from here.
Hope you find them useful!!
I use it in raspberry pi, and the first answer doesn't work for me, maybe because I typed wrong or something? I don't know. So I combined the above answers and came up with this:
now=$(date +'%Y-%m-%d')
geany "OptionalName-${now}.txt"
That if you want to use geany or anything else
a bit more convoluted solution that fully matches your spec
echo `expr $FILENAME : '\(.*\)\.[^.]*'`_`date +%d-%m-%y`.`expr $FILENAME : '.*\.\([^.]*\)'`
where first 'expr' extracts file name without extension, second 'expr' extracts extension

Resources