Format string on Linux and Solaris - solaris

I have a Korn Shell script, and one part of it is that it takes a given date in YYYYMMDD format and outputs it in YYYY/MM/DD format. At first I tried
typeset displaystart=`date --date="${gbegdate}" '+%Y/%m/%d'`
which works fine on Linux, but Solaris's date doesn't have a --date option. I then tried
typeset displaystart=`echo ${gbegdate:0:4}`/`echo ${gbegdate:4:2}`/`echo ${gbegdate:6:2}`
which also works on Linux, but on Solaris it just outputs //.
How can I format this date string in a way that works on Linux and Solaris?

The ${variable:start:length} extension to POSIX shell syntax was introduced in the version of ksh released in 1993, precisely named ksh93, and was also introduced in bash 1.13 the very same year.
The Advanced bash scripting guide from the Linux Documentation Project states:
Variable expansion / Substring replacement
These constructs have been adopted from ksh.
${var:pos}
Variable var expanded, starting from offset pos.
${var:pos:len}
Expansion to a max of len characters of variable var,
from offset pos. See Example A-13 for an example of the creative use
of this operator.
The issue is that on Solaris 10 and older, /bin/ksh is providing a previous ksh standard, ksh88, which didn't implemented this feature.
On the other hand, on Linux, ksh is often ksh93 which supports substring extraction. That explains why your script works under Linux ksh (if you really tested it on ksh.)
An old derivative of ksh93 is available on Solaris 10 though. It is named dtksh ans is located in /usr/dt/bin/dtksh. Your command should work unchanged with it however I wouldn't recommend to fully switch to dtksh, this shell being phased out from Solaris but you might still use it from a regular ksh script to workaround your issue:
typeset displaystart=$(/usr/dt/bin/dtksh -c "gbedate=$gbedate; echo \${gbegdate:0:4}/\${gbegdate:4:2}/\${gbegdate:6:2}")
Note that Solaris 11 and newer provide both GNU date and ksh93 so you wouldn't have that issue in the first place.

Korn shell doesn't have ${variable:start:length} syntax; this is a bash extension to POSIX shell syntax.
You can use echo "$variable" | cut -cstart-end instead.
typeset displaystart=`echo $gbegdate | cut -c1-4`/`echo $gbegdate | cut -c5-6`/`echo $gbegdate | cut -c7-8`
Or maybe you could change your script to use bash instead of ksh.

Related

Pipe and Redirection in UEFi-Shell does not work

In order to do simple checks (e.g. date) without using files I tried the following (without sucess):
Store date in enviroment variable:
fs0:\> date >v date_var
Shell: Incorrect redirection syntax - '>v'
as an alternative I tried to pipe the result of date:
fs0:\> date | check_date.nsh
date: Too many arguments
Do I need certain lib or command level to run the above character sequences?
I´m using a uefi shell with:
EFI Shell version 2.40 [5.10]
Current running mode 1.1.2
...
fs0:\> ver
EFI Specification Revision : 2.40
Uefi_Shell_Spec_2_2 chapter 3.4.4 let me think that both should work fine.
If I remember correctly, UEFI shell does not support process piping, nor variable piping, so you cannot chain outputs, but it do support file redirections.
try to use data > date_file.

Using SED on MAC (zsh) to get first jpg after marker string

Please Note: I found other gnu implementations of this, but they don't seem to work on a mac. This question is specifically for MacOS running zsh
I'm trying to pipe some output into SED and use it to find the first jpg after a marker string.
Here is my sample .sh file:
Phrase="where is \“frankenstien\" tonight.jpg with my hamburger tomorrow.jpg"
echo $Phrase | sed 's/.*\frankenstien" \(.*\)jpg/\1/'
The marker string is “frankenstien" (WITH quotes). I would like the output to be:
tonight.jpg
But instead its
tonight.jpg with my hamburger tomorrow.
So obviously the sequence passed to SED is wrong, how should I write it so that it stops after the first jpg AND includes the ".jpg" in it? I found many examples online of similar things but they did not work for MAC running zsh. Can the same code work on macs running bash? If you only get it to work on bash that might be good enough.
Thanks!
If the first jpg, is immediately following the frankenstien string (marker), then you can modify your regex to do below. The following should work on any POSIX compliant sed as it does not involve any constructs from the GNU version
sed 's/.*\"frankenstien\" \([^ ]*\).*/\1/'
The above regex will capture the string after the marker string and up to the subsequent space following the required string and ignore the rest.
P.S. Note that the shell versions don't play a role in how your regex string is interpreted by your sed installed. Remember sed is a binary on its own and comes shipped with your native distro (GNU on Linux and BSD on MacOS). There are few features supported in one and not in the other ( GNU vs *BSD ), but as such the native shell should not come into the picture here. E.g. In MacOS, with a default shell say zsh, you can have both BSD sed (shipped default) and GNU version (installable using homebrew).
how should I write it so that it stops after the first jpg AND includes the ".jpg" in it?
Match up until a space.
sed 's/.*frankenstien" \([^ ]*\) .*/\1/' <<<"$Phrase"
Handle tab also:
sed 's/.*frankenstien" \([^[:space:]]*\)[[:space:]].*/\1/' <<<"$Phrase"

Run sha256sum (from Cygwin) on file with special character and blank (quoting does not work)

I have Cygwin installed in order to use Linux command line tools on Windows. I also added it to my PATH. In general, it works fine, but I observe this weird behavior:
I want to run sha256sum on the file C:\Users\s1504gl\Desktop\Täst .txt. Note the german Umlaut ä and the whitespace before the file extension. In order to avoid problems with paths, I always quote paths in command line calls, such as:
sha256sum "C:\Users\s1504gl\Desktop\Täst .txt"
However, PowerShell returns
/usr/bin/sha256sum: '"C:\Users\s1504gl\Desktop\T'$'\303\244''st .txt"': No such file or directory
When I rename the file to either Täst.txt or Test .txt, it works. So the combination of the special character ä and the whitespace seems to cause the problem. Exchanging double quotes by single quotes does not change anything in this case.
I am pretty sure it has to to with PowerShell since the example works without any problems on my Linux machine.
Is there some other way of escaping special characters and/or blanks that I do not know?
Run from Cygwin terminal
sha256sum "/cygdrive/C/Users/s1504gl/Desktop/Täst\ .txt"
In general Cygwin program do not accept Windows paths and works surely with POSIX path
I found the following workaround:
I create a temporary file from R, containing all the necessary commands and then run this tempfile using bash which is also included in Cygwin. This way, I escape from the problem occurring due to different encodings in Windows and the Linux tools from Cygwin.

Need to convert ksh command line to sh

I'm trying to do a simple operation in ksh that I need to repeat in sh (Bourne shell)
All I want to do is append the contents of the first line of hte pay_period.txt file to the end of the new file name. This works great in ksh, but does not work in bourne. The program I'm using defaults to sh and I can't change that. Also I can't have actual shell scipts in the directories. So I have to issue commands.
How can I make the equivalent command below work in bourne
mv HEPAY.txt HE_PAY"$(/usr/bin/head -1 pay_period.txt)."txt
The results of $(/usr/bin/head -1 pay_period.txt) is 20140101.
If you are really talking about a real Bournce shell then you need to use backticks for command substitution ($() is POSIX and portable among "modern", POSIX-compliant shells but won't work in old, legacy shells), e.g.
mv HEPAY.txt HE_PAY`/usr/bin/head -1 pay_period.txt`.txt
Other than that I see no reason why this should not work.
PS: Note that head -1 isn't POSIX-compliant either (head -n 1 is).

Rename multiple files from command line [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Renaming lots of files in Linux according to a pattern
I have multiple files in this format:
file_1.pdf
file_2.pdf
...
file_100.pdf
My question is how can I rename all files, that look like this:
file_001.pdf
file_002.pdf
...
file_100.pdf
I know you can rename multiple files with 'rename', but I don't know how to do this in this case.
You can do this using the Perl tool rename from the shell prompt. (There are other tools with the same name which may or may not be able to do this, so be careful.)
rename 's/(\d+)/sprintf("%03d", $1)/e' *.pdf
If you want to do a dry run to make sure you don't clobber any files, add the -n switch to the command.
note
If you run the following command (linux)
$ file $(readlink -f $(type -p rename))
and you have a result like
.../rename: Perl script, ASCII text executable
then this seems to be the right tool =)
This seems to be the default rename command on Ubuntu.
To make it the default on Debian and derivative like Ubuntu :
sudo update-alternatives --set rename /path/to/rename
Explanations
s/// is the base substitution expression : s/to_replace/replaced/, check perldoc perlre
(\d+) capture with () at least one integer : \d or more : + in $1
sprintf("%03d", $1) sprintf is like printf, but not used to print but to format a string with the same syntax. %03d is for zero padding, and $1 is the captured string. Check perldoc -f sprintf
the later perl's function is permited because of the e modifier at the end of the expression
If you want to do it with pure bash:
for f in file_*.pdf; do x="${f##*_}"; echo mv "$f" "${f%_*}$(printf '_%03d.pdf' "${x%.pdf}")"; done
(note the debugging echo)