Consider the following xargs command which is working perfectly:
$ sort listing.txt | xargs -n 3 --verbose rename -n -v 's#/([^/]*)/\d_(\d{3})\.jpg#/$1/$1-$2.jpg#gi'
rename -n -v 's#/([^/]*)/\d_(\d{3})\.jpg#/$1/$1-$2.jpg#gi' 1.jpg 2.jpg 3.jpg
rename -n -v 's#/([^/]*)/\d_(\d{3})\.jpg#/$1/$1-$2.jpg#gi' 4.jpg 5.jpg 6.jpg
rename -n -v 's#/([^/]*)/\d_(\d{3})\.jpg#/$1/$1-$2.jpg#gi' 7.jpg 8.jpg 9.jpg
For simplicity I'm using a very short listing.txt. I'm using --verbose
in order to see the commands being run, and (in this simplified example) none of the commands return any output hence there's no further output here.
xargs has very primitive multi-process support however I'm trying to migrate to GNU Parallel instead because it's much more robust in terms of multi-process support
This is as close as I've come (I had to add additional double quotes in order to avoid errors, as well as add a {}
to prevent the output from being corrupted even worse), however, the output is corrupt:
$ sort listing.txt | parallel -n 3 --verbose "rename -n -v 's#/([^/]*)/\d_(\d{3})\.jpg#/$1/$1-$2.jpg#gi' {} "
rename -n -v 's#/([^/]*)/\d_(\d3.jpg)\.jpg#//-.jpg#gi' 1.jpg 2.jpg 3.jpg
rename -n -v 's#/([^/]*)/\d_(\d6.jpg)\.jpg#//-.jpg#gi' 4.jpg 5.jpg 6.jpg
rename -n -v 's#/([^/]*)/\d_(\d9.jpg)\.jpg#//-.jpg#gi' 7.jpg 8.jpg 9.jpg
It looks like parallel is taking the regex that is supposed to be passed unmodified into the rename command and attempting to do unwanted processing on it
For example, the {3}
in the regex is being substituted for filenames from the input list, and the $1
and $2
are being removed
I tried adding --
like this:
sort listing.txt | parallel -n 3 --verbose -- "rename -n -v 's#/([^/]*)/\d_(\d{3})\.jpg#/$1/$1-$2.jpg#gi' {} "
but no improvement
I can make a bit of progress by backslashing the $1
and $2
:
sort listing.txt | parallel -n 3 --verbose "rename -n -v 's#/([^/]*)/\d_(\d{3})\.jpg#/\$1/\$1-\$2.jpg#gi' {} "
rename -n -v 's#/([^/]*)/\d_(\d3.jpg)\.jpg#/$1/$1-$2.jpg#gi' 1.jpg 2.jpg 3.jpg
rename -n -v 's#/([^/]*)/\d_(\d6.jpg)\.jpg#/$1/$1-$2.jpg#gi' 4.jpg 5.jpg 6.jpg
rename -n -v 's#/([^/]*)/\d_(\d9.jpg)\.jpg#/$1/$1-$2.jpg#gi' 7.jpg 8.jpg 9.jpg
But attempting to backslash the {3}
doesn't work because it passes the backslashes into the resulting commands:
$ sort listing.txt | parallel -n 3 --verbose "rename -n -v 's#/([^/]*)/\d_(\d\{3\})\.jpg#/\$1/\$1-\$2.jpg#gi' {} "
rename -n -v 's#/([^/]*)/\d_(\d\{3\})\.jpg#/$1/$1-$2.jpg#gi' 1.jpg 2.jpg 3.jpg
rename -n -v 's#/([^/]*)/\d_(\d\{3\})\.jpg#/$1/$1-$2.jpg#gi' 4.jpg 5.jpg 6.jpg
rename -n -v 's#/([^/]*)/\d_(\d\{3\})\.jpg#/$1/$1-$2.jpg#gi' 7.jpg 8.jpg 9.jpg
What I really want is to disable all this special processing of the input that parallel is apparently doing that xargs does not. I've read through the parallel man page but haven't found anything useful yet.
I found a --quote
option to parallel which seemed promising but it made things so much worse:
$ sort listing.txt | parallel -n 3 --verbose --quote "rename -n -v 's#/([^/]*)/\d_(\d{3})\.jpg#/$1/$1-$2.jpg#gi' {} "
'rename -n -v '"'"'s#/([^/]*)/\d_(\d3.jpg)\.jpg#//-.jpg#gi'"'"' 1.jpg' 2.jpg '3.jpg '
'rename -n -v '"'"'s#/([^/]*)/\d_(\d6.jpg)\.jpg#//-.jpg#gi'"'"' 4.jpg' 5.jpg '6.jpg '
/usr/bin/bash: line 1: rename -n -v 's#/([^/]*)/\d_(\d3.jpg)\.jpg#//-.jpg#gi' 1.jpg: No such file or directory
'rename -n -v '"'"'s#/([^/]*)/\d_(\d9.jpg)\.jpg#//-.jpg#gi'"'"' 7.jpg' 8.jpg '9.jpg '
/usr/bin/bash: line 1: rename -n -v 's#/([^/]*)/\d_(\d6.jpg)\.jpg#//-.jpg#gi' 4.jpg: No such file or directory
/usr/bin/bash: line 1: rename -n -v 's#/([^/]*)/\d_(\d9.jpg)\.jpg#//-.jpg#gi' 7.jpg: No such file or directory
Using --quote
but deleting some of the extra quotation marks I added earlier, it's a bit more promising:
$ sort listing.txt | parallel -n 3 --verbose --quote rename -n -v 's#/([^/]*)/\d_(\d{3})\.jpg#/$1/$1-$2.jpg#gi' {}
rename -n -v 's#/([^/]*)/\d_(\d3.jpg)\.jpg#/$1/$1-$2.jpg#gi' 1.jpg 2.jpg 3.jpg
rename -n -v 's#/([^/]*)/\d_(\d6.jpg)\.jpg#/$1/$1-$2.jpg#gi' 4.jpg 5.jpg 6.jpg
rename -n -v 's#/([^/]*)/\d_(\d9.jpg)\.jpg#/$1/$1-$2.jpg#gi' 7.jpg 8.jpg 9.jpg
This keeps the $1
and $2
intact without having to backslash them, BUT the core issue of the {3}
being replaced
And yes I know I could rewrite my regex, i.e. replacing \d{3}
with \d\d\d
or similar, but this is just an example, I have many more commands with the same or similar issues and I'd prefer not to rewrite them all.