renaming a file with regex in bash MacOSX - regex

I have file names like this
223h123.sdsdas.png
which I would like to rename to
sdsdas.png
I am using this command
for i in *.png;do mv "$i" "${i/[a-zA-Z0-9]*/}";done
which gives me this instead
png,
I am using bash on MacOS X.

You're confusing regular expressions with Parameter Expansion. They look a bit similar, but they are not the same.
A regular expression parser might allow you to make a regex-based substitution, for example:
[ghoti#pc ~]$ i="223h123.sdsdas.png"
[ghoti#pc ~]$ echo "$i" | sed 's/^[^.]*\.\([^.]*\)/\1/'
sdsdas.png
[ghoti#pc ~]$
Sed, the Stream Editor, has a substitute command that takes a Basic Regular Expression and replaces \1 with the first bracketed atom of the regex.
Alternately, you could use parameter expansion to strip off text to the first dot.
[ghoti#pc ~]$ i="223h123.sdsdas.png"
[ghoti#pc ~]$ echo ${i#*.}
sdsdas.png
[ghoti#pc ~]$

Related

Cross platform regex substring match for git

Sorry for yet another pattern matching question, but I'm struggling to to find a tool that will do a regex in a git hook. It needs to work on Windows, Mac and Linux.
This gnu grep works for Windows and Linux, but not Mac (because bsd)
echo "feature/EOPP-234-foo" | grep -Po -e '[A-Z]{4}-\d{1,5}'
This works for Mac and Linux, but not windows (because <git>\usr\bin\egrep don't seem to work)
echo "feature/EOPP-234-foo" | egrep -o '[A-Z]{4}-\d{1,5}'
sed might be the most common tool, but stuffed if I can get it to match:
echo "feature/EOPP-234-foo" | sed -n 's/^.*\([A-Z]{4}\-\d{1,5}\).*$/\1/p'
I've even tried bash matching with no luck
[[ "feature/EOPP-234-foo" =~ ([A-Z]{4}-\d{1,5}) ]] && echo ${BASH_REMATCH[1]}
Any ideas?
When you need to make POSIX tools run on Windows, you need to remember to use double quotation marks around your commands, not single quotes.
Also, you can use a common POSIX ERE compliant regex across all these environments. This means \d must be replaced with [0-9] or [[:digit:]] as \d is a PCRE only compliant construct.
You can use
grep -Eo "[A-Z]{4}-[0-9]{1,5}"
grep -Eo "[A-Z]{4}-[[:digit:]]{1,5}"

pattern matching while using ls command in bash script

In a sh script, I am trying to loop over all files that match the following pattern
abc.123 basically abc. followed by only numbers, number following . can be of any length.
Using
$ shopt -s extglob
$ ls abc.+([0-9])
does the job but on terminal and not through the script. How can I get only files that match the pattern?
if I understood you right, the pattern could be translated into regex:
^abc\.[0-9]+$
so you could
keep using ls and grep the output. for example:
ls *.*|xargs -n1|grep -E '^abc\.[0-9]+$'
or use find
find has an option -regex
If you're using sh and not bash, and presumably you also want to be POSIX compliant, you can use:
for f in ./*
do
echo "$f" | grep -Eq '^\./abc.[0-9]+$' && continue
echo "Something with $f here"
done
It will work fine with filenames with spaces, quotes and such, but may match some filenames with line feeds in them that it shouldn't.
If you tagged your question bash because you're using bash, then just use extglob like you described.

Making a mistake with | (or) in regular expressions

I'm sure I'm doing something really obviously wrong here, but I can't figure out what. Using grep from a bash shell, I have a file test.txt:
ABC123
ABC456
ABC789
DEF123
DEF456
DEF789
Now at the command line:
$ grep ABC test2.txt
ABC123
ABC456
ABC789
$ grep DEF test2.txt
DEF123
DEF456
DEF789
So those work great. Now, I expect the following command to print the whole file, but:
$ grep ABC\|DEF test2.txt
$ grep (ABC)\|(DEF) test2.txt
-bash: syntax error near unexpected token `ABC'
$ grep \(ABC\)\|\(DEF\) test2.txt
$ grep 'ABC|DEF' test2.txt
What am I doing wrong?
Turn on the extended regex with -E:
grep -E "ABC|DEF" test2.txt
As others have pointed out, standard grep command does not support the or syntax. Unfortunately, from there, things are a mishmash.
Some systems have a egrep that does offer or syntax.
Some systems can use a -E or -P (for Perl) flag to extend grep syntax.
Some systems have both the -E and egrep that do the same thing. This implies that there are systems out there where grep -E and egrep are not the same. (sad but true).
Some systems now use the extended regular expressions in their standard grep command. Apparently, your system doesn't.
Read your manpages to see what your system does support. Some systems have a manpage for re_formatthat will explain what they support and don't support in extended format.
Then again, you could always just use a Perl one-liner:
$ perl -ne "print if /(ABC)|(DEF)/" test.txt
At least you know all the stuff that supports.
I don't think standard syntax supports it. You could use -P switch if available:
grep -P "(ABC|DEF)" test2.txt
Use egrep instead, which is the same as using grep -E:
egrep 'ABC|DEF' test2.txt

grep with regexp: whitespace doesn't match unless I add an assertion

GNU grep 2.5.4 on bash 4.1.5(1) on Ubuntu 10.04
This matches
$ echo "this is a line" | grep 'a[[:space:]]\+line'
this is a line
But this doesn't
$ echo "this is a line" | grep 'a\s\+line'
But this matches too
$ echo "this is a line" | grep 'a\s\+\bline'
this is a line
I don't understand why #2 does not match (whereas # 1 does) and #3 also shows a match. Whats the difference here?
Take a look at your grep manpage. Perl added a lot of regular expression extensions that weren't in the original specification. However, because they proved so useful, many programs adopted them.
Unfortunately, grep is sometimes stuck in the past because you want to make sure your grep command remains compatible with older versions of grep.
Some systems have egrep with some extensions. Others allow you to use grep -E to get them. Still others have a grep -P that allows you to use Perl extensions. I believe Linux systems' grep command can use the -P extension which is not available in most Unix systems unless someone has replaced the grep with the GNU version. Newer versions of Mac OS X also support the -P switch, but not older versions.
grep doesn't support the complete set of regular expressions, so try using -P to enable perl regular expressions. You don't need to escape the + i.e.
echo "this is a line" | grep -P 'a\s+line'

How to go from a multiple line sed command in command line to single line in script

I have sed running with the following argument fine if I copy and paste this into an open shell:
cat test.txt | sed '/[,0-9]\{0,\}[0-9]\{1,\}[acd][0-9]\{1,\}[,0-9]\{0,\}/{N
s/[,0-9]\{0,\}[0-9]\{1,\}[acd][0-9]\{1,\}[,0-9]\{0,\}\n\-\-\-//}'
The problem is that when I try to move this into a KornShell (ksh) script, the ksh throws errors because of what I think is that new line character. Can anyone give me a hand with this? FYI: the regular expression is supposed to be a multiple line replacement.
Thank you!
This: \{0,\} can be replaced by this: *
This: \{1,\} can be replaced by this: \+
It's not necessary to escape hyphens.
The newline can be replaced by -e (or by a semicolon)
The cat can be replaced by using the filename as an argument to sed
The result:
sed -e '/[,0-9]*[0-9]\+[acd][0-9]\+[,0-9]*/{N' -e 's/[,0-9]*[0-9]\+[acd][0-9]\+[,0-9]*\n---//}' test.txt
or
sed '/[,0-9]*[0-9]\+[acd][0-9]\+[,0-9]*/{N;s/[,0-9]*[0-9]\+[acd][0-9]\+[,0-9]*\n---//}' test.txt
(untested)
can you try to put your regex in a file and call sed with the option -f ?
cat test.txt | sed -f file.sed
Can you try to replace the new line character with `echo -e \\r`
The Korn Shell - unlike the C Shell - has no problem with newlines in strings. The newline is very unlikely to be your problem, therefore. The same comments apply to Bourne and POSIX shells, and to Bash. I've copied your example and run it on Linux under both Bash and Korn shell without any problem.
If you use C Shell for your work, are you sure you're running 'ksh ./script' and not './script'?
Otherwise, there is some other problem - an unbalanced quote somewhere, perhaps.
Check out the '-v' and '-n' options as well as the '-x' option to the Korn Shell. That may tell you more about where the problem is.