Rename multiple files with /usr/bin/rename using regex - regex

I have a lot of pdfs that I want to rename with /usr/bin/rename.
The files are named in the following pattern:
<rating> <a pretty long title> (<author> <year>).pdf
e.g.: +++ The discovery of some very interesting stuff (Dude 1999).pdf
rating: 1 to 5 '+' signs
year: numerical
They should be renamed into the following pattern:
<author>, <year> <rating> <a pretty long title>.pdf
e.g.: Dude, 1999 +++ The discovery of some very interesting stuff.pdf
I tried to use /usr/bin/rename and wrote this command:
rename 's/(.*)\ (.*)\ \((.*)\ (.*)\).pdf/$3, $4 $1 $2.pdf/' *.pdf
However, the command does not consider that the rating always contains '+' signs and that the year is always numerical. How can I achieve this? I tried something like ([+]{1,5}) and ([0-9]{4}), but it didn't work.
Is rename actually able to interpret something other than (.*) as the input for the variables $1 ... $n?
Thanks for your help!

This works fine for me:
rename 's/(\+{1,5}) (.*) \((.*) ([0-9]{4})\).pdf/$3, $4 $1 $2.pdf/' -- \
'Dude, 1999 +++ The discovery of some very interesting stuff.pdf'
... however your question doesn't quote the error message, so it's hard to tell what might be wrong in your situation.
Just as a warning, there are two different versions of /usr/bin/rename that are widely found on Linux systems, and which have different syntaxes. I assume that you are using the Perl one, however, since your original command worked at all. That means that you can use any Perl expression to modify the name - see perlre for more details.

Unfortunately Fedora (it's my distro) has worthless version of rename.
But I have changed it for perl version of replace utility.
You can find it at CPAN
get and untar archive and then:
# ./Build installdeps
# sudo ./Build install
!!! It actions replace original fedora rename: bin file and manual, but it can be reverted by yum reinstall and may be reverted at next fedora update
Also you can install it separately or use alternatives.

Related

Bash Regex matches on Ubuntu but not on macOS

I have the following bash script:
#!/bin/bash
git_status="$(git status 2>/dev/null)"
branch_pattern="^(# |)On branch ([^${IFS}]*)"
echo $git_status
echo $branch_pattern
if [[ ${git_status} =~ ${branch_pattern} ]]; then
echo 'hello'
echo $BASH_REMATCH
fi
Here is the output when I run the script on Ubuntu with bash version 4:
On branch master Initial commit Untracked files: (use "git add <file>..." to include in what will be committed) test.sh nothing added to commit but untracked files present (use "git add" to track)
^(# |)On branch ([^ ]*)
hello
On branch master
However, when I run the same script on macOS with bash version 3, the regex does not match, and nothing inside the if block is executed. The rest of the output is identical. What am I missing? Does my regex need to be formatted differently on macOS/in this version of bash? Is there a flag I am missing?
I have seen similar posts about differences in regex behavior across platforms for e.g., the find command, but I have not yet found a post relevant to my issue.
It looks to me like there's a bug in the RE engine in the version of bash that macOS comes with (it's rather old -- 3.2.57). It's something to do with the ^(# |) part -- it doesn't seem to match an empty string at the beginning of the string, as it should. But I found a workaround. Apparently the bug doesn't happen if the ^ is inside the parentheses, like this:
branch_pattern="(^# |^)On branch ([^${IFS}]*)"
BTW, you shouldn't use echo $varname to print the contents of a variable. For one thing, it'll do word splitting (converting all runs of whitespace into single spaces) and wildcard expansion on the value, which can be very confusing/misleading. Try something like printf '<<%q>>\n' "$varname" instead. Its output can be a little cryptic if the variable contains weird characters, but at least it'll make it clear that there are weird things in there.
If you are only trying to get the current git branch name, there is no need for regex. Git already has this built in.
git rev-parse --abbrev-ref HEAD 2>/dev/null
This will print out the current branch name (if any)
If you are in a git repository without any commits, it will only return "HEAD"

How can I capture group from string using regexp in shell in msysgit on Windows?

[Editor's note: The OP has later clarified that he's running bash as part of msysgit, the Git version for Windows.]
I'm trying to get last digits from the string. I have a little script but it doesn't work and i don't know why:
#!bin/bash
TAGS="MASTER_46"
re="_(\d+)"
if [[ ${TAGS}=~$re ]]; then
echo "Find"
echo ${BASH_REMATCH}
echo ${BASH_REMATCH[1]}
fi
The output:
Find
{empty}
{empty}
I am using bash
$ bash --version
GNU bash, version 3.1.20(4)-release
There are several problems:
bash doesn't support \d. Use [0-9].
Whitespace is needed around the operator: $TAGS =~ $re, otherwise bash parses it as [[ -n "$TAGS=~$re" ]].
Path to the shell is /bin/bash, not bin/bash.
Update, based on the OP's clarification re environment and his own findings:
tl;dr:
msysgit (as of version 1.9.5) comes with a bash executable that is compiled without support for =~, the regex-matching operator
A limited workaround is to use utilities such as grep, sed, and awk instead.
To solve this problem fundamentally, install a separate Unix emulation environment such as MSYS or Cygwin, and use git.exe (the core of msysgit) from there.
choroba's answer has great pointers, but let me add that, since you get the following error message:
conditional binary operator expected syntax error near =~
the implication is either that
your bash version is too old to support =~, the regex-matching operator.
your bash version was compiled without regex support
Given that =~ was introduced in bash 3.0 (see http://tiswww.case.edu/php/chet/bash/NEWS) and you're running 3.1.x, it must be the latter, which indeed turned out to be true:
The OP runs msysgit, the official Git version for Windows that comes with bash and a set of Unix utilities.
As it turns out, as of version 1.9.5, the bash executable that comes with msysgit is built without regex support, presumably due to technical difficulties - see https://groups.google.com/forum/#!topic/msysgit/yPh85MPDyfE.
Incredibly, the "Known Issues" section of the release notes does not mention this limitation.
Your best bet is to:
Install MSYS to use as your Unix emulation environment - its bash does come with =~ support (note that msysgit was originally forked from MSYS).
Alternatively, to get better Unix emulation and more tools at the expense of a larger installation footprint and possibly performance, install Cygwin instead.
In MSYS, use only git.exe from msysgit, via the Windows %PATH%.
To that end, be sure to install msysgit with the Run Git from the Windows Command Prompt option - see https://stackoverflow.com/a/5890222/45375
Alternatively, add C:\Program Files\Git\cmd (assumes the default path on 32-bit Windows, on 64-bit Windows it's C:\Program Files (x86)\Git\cmd) manually to your Windows %PATH%, OR extend $PATH in your MSYS ~/.profile file (e.g., PATH="$PATH:/c/program files/git/cmd").
You could hack your msysgit installation, but it hardly seems worth it and I don't know what the side effects are;
If you really wanted to try, do the following: Copy the following files from an MSYS installation's bin directory to msysgit's bin directory: bash.exe, sh.exe, msys-termcap-0.dll - in other words: replace msysgit's bash altogether.

Duplicate Perl installation on CENTOs 64 bit

I insatlled perl on my machine and on giving follows command
perl -e 'print("#INC\n");'
I get this output
/usr/local/lib/perl5/site_perl/5.18.1/x86_64-linux /usr/local/lib/perl5/site_perl/5.18.1
/usr/local/lib/perl5/5.18.1/x86_64-linux /usr/local/lib/perl5/5.18.1 .
But the MACHINE that is working properly gives follows output for the
same command
/usr/local/lib64/perl5 /usr/local/share/perl5/usr/lib64/perl5/vendor_perl
/usr/share/perl5/vendor_perl/usr/lib64/perl5 /usr/share/perl5 .
YOU CAN SEE THE DIFF INT PATH for lib & lib64
How can i correct the above ??
please help
Perl comes pre-installed on every Linux machine - maybe the machine that is working properly uses the stock perl. You can identify the location of the perl executable issuing which perl in the command line.
Also, you can check the perl version by running perl -v - if the perl on the machine that is working is older, it might be the OS perl.
Regarding the ways to manipulate the lib path, have a look at the tutorial that Gabor Szabo wrote regarding How to change #INC to find Perl modules in non-standard locations

rpm build error

I tried to build a rpm package which is giving me the following error
/usr/lib/rpm/find-debuginfo.sh /usr/src/redhat/BUILD/RPMS
find: invalid predicate `'
error: Bad exit status from /var/tmp/rpm-tmp.86590 (%install)
what could be the reason .can any one help me in this...Thanks
Try defining the BuildRoot variable in your spec file. The find-debuginfo script looks in to that directory several times, and will die without it.
This will usually look something like: BuildRoot: %{_tmpdir}/%{name}-%{version}-%{release}
As to your second question, I can't say without seeing spec file and sources directly, and I am by no means an RPM expert. I will recommend you to Chapter 13 of Maximum RPM(there are copies available free online), and the notes from Tom Callaway's presentation on How to make good RPM packages - I've found the spec examples here to be very helpful in the past.
In your spec you can do this at the top:
%define debug_package %{nil}
This should bypass this problem
I just hit this same problem when attempting to build on a RedHat 5.3 server. Here is what I found. The error appears to be caused by an empty RPM_BUILD_ROOT variable. Below is one offending line:
find "$RPM_BUILD_ROOT" ! -path "${debugdir}/*.debug" -type f \
\( -perm -0100 -or -perm -0010 -or -perm -0001 \) \
-print |
If RPM_BUILD_ROOT hasn't been defined, then the first argument to find is an empty string "", which causes this error. Interestingly enough, if you remove the quotes from around $RPM_BUILD_ROOT, then command works fine since the first argument would become the "!". Since it's not required to define a "BuildRoot:" in the spec file, this certainly looks like a bug to me.

Is there any way to get readable gcc error and warning output at the command line?

For some long errors, the gcc output is dense and has lots of line-wrapping etc. Especially when errors are subtle, it can take me 10-30 seconds of squinting to parse it with my eyes.
I've taken to pasting this in an open code-editor window to get some basic syntax highlighting and enable reformatting with regex's.
Has anyone invented a more automated method?
I use this script, called colorize:
#!/bin/bash
while read x ; do echo $x ; done \
| sed -e "s/.*error:.*/\x1b[1;36m&\x1b[0m/" \
-e "s/.*warning:.*/\x1b[1;36m&\x1b[0m/" \
-e "s/^\(.*\)\(required from\)/\x1b[1;36m\1\x1b[0mnote: \2/" \
-e "s/^\(.*\)\(In instantiation of\)/\x1b[1;36m\1\x1b[0mnote: \2/" \
-e "s/^\(.*\)\(In member\)/\x1b[1;36m\1\x1b[0mnote: \2/" \
| sed -e "s/error:/\x1b[1;31m&\x1b[1;36m/" \
-e "s/warning:/\x1b[1;35m&\x1b[1;36m/" \
-e "s/note:/\x1b[1;30m&\x1b[0m/"
Then I just call it like this(using make or whatever build system):
make |& colorize
And I get color output similar to clang.
I've found colorgcc to be invaluable. By introducing coloring, it becomes much easier to mentally parse the text of gcc error messages, especially when templates are involved.
If your errors are template related, take a look at STLfilt:
http://www.bdsoft.com/tools/stlfilt.html
gccfilter does coloring & simplification of messages.
http://www.mixtion.org/gccfilter/
If you use GCC 4.9, you can add -fdiagnostics-color=auto as an additonal compilation flag. At some later version, the color has been enabled by default.
check diagcc out, you can get something like this:
If your gcc ≥ 4.9, you can use argument -fdiagnostics-color=always.
To answer your question 4 years later, clang should be mentioned here.
Here's my current hack, which mostly inserts newlines and indentation in strategic locations along with a little extra annotation, but does nothing to address STL verbosity.
Note that as currently implemented, this script does not return an error if the compiler returned one, so doing something like this will not work properly: (make && ./runApplication). This could surely be remedied by someone with better bash-fu.
#!/bin/bash
# SUBSTITUTION RULES:
# Note: All substitution rules must end in a semi-colon, inside of the closing quote
subColonSpace='s/: /:\n /g;'
subSrc='s/^src/\nsrc/;'
subError='s/error:/error:\n\n======================================\nERROR:/;'
subWarning='s/ *error: *\n/ERROR: /;'
subWarning='s/ *warning: *\n/WARNING: /;'
subNote='s/note:/\n NOTE:/g;'
subOpenTic='s/‘/\n ‘/g;'
subOpenParen='s/(/(\n /g; s/(\n *)/()/g;'
subCommaSpace='s/, /,\n /g;'
# Note: The order of these may matter
sedExpr="$subColonSpace $subSrc $subError $subWarning $subNote $subOpenTic
$subOpenParen $subCommaSpace"
makelogFile=makelog.tmp
make "$#" 2>&1 | sed "$sedExpr" | tee $makelogFile
if you like Ruby there is GilCC! GilCC is very easy to install (just copy it to the bin folder) and easy to use (just type GilCC instead of "gcc" or "make") and it works with GCC version. Unlike Perl based scripts GilCC has statistics such as # of warnings and error and compile time. You don't have to mess with .bash files and it is cross platform as long as you can run Ruby on your machine. Since it has the power of Ruby; you can make GilCC do different things such as trigger test automation, unit test or program external hardware after a successful build.
Here is the link to the download page: http://www.onlysolutionssoftware.com/gilcc/