How to match beginning of variable in dash - sh

Is it possible to match beginning of string in dash (/bin/sh)?
This is the usual situation
var="Hello"
if [ "$var" = "Hello" ]; then echo "Match"; fi
But sometimes it could be "Hello World", "Hello Kitty" or something like that.
Tried with asterisks here and there (eg. "Hello*"), but no luck so far.

Use case with glob.
case "$var" in
"Hello"*) echo "Match"; ;;
esac

Related

Bash String Comparison With Regex Not Working

I'm trying to do a simple string comparison in zsh where one the arguments is the result of a sed call.
Yet I keep getting "zsh: missing end of string"
[ (sed -En s/'(^.+)-SNAPSHOT'/'\1'/p ./app_version.txt) = "1.20.11" ]
The app_version.txt file contains a Maven version. sed is stripping out "SNAPSHOT".
app_version.txt
1.20.11-SNAPSHOT
It's because the output of your sed needs to be double quoted. Try this:
[ "$(sed -En s/'(^.+)-SNAPSHOT'/'\1'/p ./app_version.txt)" = "1.20.11" ]
In your case, you don't even need regular expressions. You could do it with
if [[ $(<app_version.txt) == 1.20.11-SNAPSHOT ]]
or, if you want to make the SNAPSHOT part optional, something like
if [[ $(<app_version.txt) == 1.20.11-* ]]

how to use * in sh string comparison

How to correctly use * in sh? I tried googling it but couldn't find anything. The following echo ture. why is that?
file="test test"
if [ "$file" != "te"* ]
then
echo true
else
echo false
fi
To avoid all the potential problems, when using POSIX shell, you should consider using the old expr regex or match expressions. Your choices are:
#!/bin/sh
file="test test"
if [ $(expr "$file" : "te.*") -gt 0 ]
then
echo true
else
echo false
fi
or
if [ $(expr substr "$file" 1 2) = "te" ]
then
echo true
else
echo false
fi
Not elegant, but they are the proper tools for the shell. A short explanation of each and the expr syntax for each is:
string : regularExp : returns the length of string if both sides match,
returns 0 otherwise
match string regularExp : same as the previous one
substr string start length : returns the substring of string starting from
start and consisting of length characters
I did a bit of googling and found a good bash scripting resource:
Advanced Bash-Scripting Guide
There is a segment that answers your question:
[[ $a == z* ]] # True if $a starts with an "z" (pattern matching).
[[ $a == "z*" ]] # True if $a is equal to z* (literal matching).
[ $a == z* ] # File globbing and word splitting take place.
[ "$a" == "z*" ] # True if $a is equal to z* (literal matching).
So in your case the condition should be:
if [[ file != te* ]]

How to remove YAML frontmatter from markdown files?

I have markdown files that contain YAML frontmatter metadata, like this:
---
title: Something Somethingelse
author: Somebody Sometheson
---
But the YAML is of varying widths. Can I use a Posix command like sed to remove that frontmatter when it's at the beginning of a file? Something that just removes everything between --- and ---, inclusive, but also ignores the rest of the file, in case there are ---s elsewhere.
I understand your question to mean that you want to remove the first ----enclosed block if it starts at the first line. In that case,
sed '1 { /^---/ { :a N; /\n---/! ba; d} }' filename
This is:
1 { # in the first line
/^---/ { # if it starts with ---
:a # jump label for looping
N # fetch the next line, append to pattern space
/\n---/! ba; # if the result does not contain \n--- (that is, if the last
# fetched line does not begin with ---), go back to :a
d # then delete the whole thing.
}
}
# otherwise drop off the end here and do the default (print
# the line)
Depending on how you want to handle lines that begin with ---abc or so, you may have to change the patterns a little (perhaps add $ at the end to only match when the whole line is ---). I'm a bit unclear on your precise requirements there.
If you want to remove only the front matter, you could simply run:
sed '1{/^---$/!q;};1,/^---$/d' infile
If the first line doesn't match ---, sed will quit; else it will delete everything from the 1st line up to (and including) the next line matching --- (i.e. the entire front matter).
If you don't mind the "or something" being perl.
Simply print after two instances of "---" have been found:
perl -ne 'if ($i > 1) { print } else { /^---/ && $i++ }' yaml
or a bit shorter if you don't mind abusing ?: for flow control:
perl -ne '$i > 1 ? print : /^---/ && $i++' yaml
Be sure to include -i if you want to replace inline.
you use a bash file, create script.sh and make it executable using chmod +x script.sh and run it ./script.sh.
#!/bin/bash
#folder articles contains a lot of markdown files
files=./articles/*.md
for f in $files;
do
#filename
echo "${f##*/}"
#replace frontmatter title attribute to "title"
sed -i -r 's/^title: (.*)$/title: "\1"/' $f
#...
done
This AWK based solution works for files with and without FrontMatter, doing nothing in the later case.
#!/bin/sh
# Strips YAML FrontMattter from a file (usually Markdown).
# Exit immediately on each error and unset variable;
# see: https://vaneyckt.io/posts/safer_bash_scripts_with_set_euxo_pipefail/
set -Ee
print_help() {
echo "Strips YAML FrontMattter from a file (usually Markdown)."
echo
echo "Usage:"
echo " `basename $0` -h"
echo " `basename $0` --help"
echo " `basename $0` -i <file-with-front-matter>"
echo " `basename $0` --in-place <file-with-front-matter>"
echo " `basename $0` <file-with-front-matter> <file-to-be-without-front-matter>"
}
replace=false
in_file="-"
out_file="/dev/stdout"
if [ -n "$1" ]
then
if [ "$1" = "-h" ] || [ "$1" = "--help" ]
then
print_help
exit 0
elif [ "$1" = "-i" ] || [ "$1" = "--in-place" ]
then
replace=true
in_file="$2"
out_file="$in_file"
else
in_file="$1"
if [ -n "$2" ]
then
out_file="$2"
fi
fi
fi
tmp_out_file="$out_file"
if $replace
then
tmp_out_file="${in_file}_tmp"
fi
awk -e '
BEGIN {
is_first_line=1;
in_fm=0;
}
/^---$/ {
if (is_first_line) {
in_fm=1;
}
}
{
if (! in_fm) {
print $0;
}
}
/^(---|...)$/ {
if (! is_first_line) {
in_fm=0;
}
is_first_line=0;
}
' "$in_file" >> "$tmp_out_file"
if $replace
then
mv "$tmp_out_file" "$out_file"
fi

Check what device are You running and execute action

I've written this script:
#!/bin/sh
DEVICE=`sysctl hw.machine`
if [ $DEVICE = "hw.machine: iPhone3,1" ]
then
echo "Test Done"
else
echo "Test failed"
fi
After I run it I've got a message: ./test: line 5: [: too many arguments why isn't it working ?
You should always quote your expansions. [ is an alias for the test command. Just like any other command it takes arguments. The $DEVICE variable is expanded prior to the command running.
If $DEVICE contained whitespace, the command would look like this:
[ foo bar = "hw.machine: iPhone3,1" ]
In this example test is getting the arguments "foo" and "bar" before the comparison operator "=".
You need to quote the expansion:
if [ "$DEVICE" = "hw.machine: iPhone3,1" ]
Another note is that if using [[ in bash, this is not an issue as word splitting does not occur inside of [[.
See the following for more information on quoting: http://mywiki.wooledge.org/Quotes

cut off known substring sh

How to cut off known substring from the string in sh?
For example, I have string "http://www.myserver.org/very/very/long/path/mystring"
expression "http://www.myserver.org/very/very/long/path/" is known. How can I get "mystring"?
Thanks.
E.g. using perl:
echo "http://www.myserver.org/very/very/long/path/mystring" | perl -pe 's|^http://www.myserver.org/very/very/long/path/(.*)$|\1|'
E.g. using sed:
echo "http://www.myserver.org/very/very/long/path/mystring" | sed 's|^http://www.myserver.org/very/very/long/path/\(.*\)$|\1|'
E.g. when the search string is held in a variable, here named variable. Use double quotes to expand the variable.
echo "http://www.myserver.org/very/very/long/path/mystring" | sed "s|^${variable}\(.*\)$|\1|"
Tested under /bin/dash
$ S="http://www.myserver.org/very/very/long/path/mystring" && echo ${S##*/}
mystring
where
S is the variable-name
## remove largest prefix pattern
*/ upto the last slash
For further reading, search "##" in man dash
Some more illustrations:
$ S="/mystring/" ; echo ${S##*/}
$ S="/mystring" ; echo ${S##*/}
mystring
$ S="mystring" ; echo ${S##*/}
mystring