Search code examples
bashshellxargsparameter-expansion

renaming series of files using xargs


I would like to rename several files picked by find in some directory, then use xargs and mv to rename the files, with parameter expansion. However, it did not work...

example:

mkdir test
touch abc.txt
touch def.txt

find . -type f -print0 | \
xargs -I {} -n 1 -0 mv {} "${{}/.txt/.tx}"

Result:

bad substitution
[1]    134 broken pipe  find . -type f -print0

Working Solution:

for i in ./*.txt ; do mv "$i" "${i/.txt/.tx}" ; done

Although I finally got a way to fix the problem, I still want to know why the first find + xargs way doesn't work, since I don't think the second way is very general for similar tasks.

Thanks!


Solution

  • Remember that shell variable substitution happens before your command runs. So when you run:

    find . -type f -print0 | \
    xargs -I {} -n 1 -0 mv {} "${{}/.txt/.tx}"
    

    The shell tries to expan that ${...} construct before xargs even runs...and since that contents of that expression aren't a valid shell variable reference, you get an error. A better solution would be to use the rename command:

    find . -type f -print0 | \
    xargs -I {} -0 rename .txt .tx {}
    

    And since rename can operate on multiple files, you can simplify that to:

    find . -type f -print0 | \
    xargs -0 rename .txt .tx