简体   繁体   中英

Linux shell script to find and rename files to remove suffix?

I have some files named like this:

file1.c.keep.apple

file2.c.keep.apple

I am trying to write a shell script so that I pass in the suffix as an argument (in this case, apple ) and it will rename all of the files removing the .keep.apple .

Example execution:

script.sh apple

results in the files above being renamed to

file1.c

file2.c

So far, I have

 #! /bin/sh
 find . -type f -name \'*.keep.$1\' -print0 | xargs -0 rename 's/\(.keep.*)$//'

and the files do not get renamed. I know the find portion is correct. I am thinking the regex on my rename is wrong. How can I get the script working the way I want?

I know the find portion is correct

Except it isn't.

find . -type f -name "*.keep.$1" -print0 | ...

Updated, try this perhaps:

#!/bin/bash

SUFFIX=$1;

find . -type f -name "*keep.${SUFFIX}" | while read -r file;
do 
    nfile=`echo $file | sed "s/\.keep\.${SUFFIX}//g"`; 
    mv "$file" "$nfile" 2>/dev/null; 
done

here it is running:

jgalley@jgalley-debian:/test5$ cat replace.sh 
#!/bin/bash

SUFFIX=$1;

find . -type f -name "*keep.${SUFFIX}" | while read -r file;
do 
    nfile=`echo $file | sed "s/\.keep\.${SUFFIX}//g"`; 
    mv "$file" "$nfile" 2>/dev/null; 
done
jgalley@jgalley-debian:/test5$ find .
.
./-filewithadash.keep.apple
./dir1
./dir1/file
./dir1/file2.keep.orange
./dir2
./dir2/file2
./file with spaces
./file.keep.orange
./file.keep.somethingelse.apple
./file.orange
./replace.sh
jgalley@jgalley-debian:/test5$ ./replace.sh apple
jgalley@jgalley-debian:/test5$ find .
.
./-filewithadash
./dir1
./dir1/file
./dir1/file2.keep.orange
./dir2
./dir2/file2
./file with spaces
./file.keep.orange
./file.keep.somethingelse.apple
./file.orange
./replace.sh
jgalley@jgalley-debian:/test5$ 

I'd say you need:

find . -type f -name "*.keep.$1" -print0 | xargs -0 rename "s/\.keep\.$1$//"

Note the following limitations:

  • rename might not be available everywhere.
  • find -print0 and xargs -0 are GNU extensions which might not be available on all Unixes.
  • if your first parameter contains characters that are special for regexes the result might not what you want. (eg yourscript "a*e" )

If you can assume bash, and a version of bash greater then 4 (with globstar support), here is a clean bash-only solution:

#!/usr/bin/env bash

(($#)) || exit 1

shopt -s globstar nullglob
for f in **/*.keep."$1"; do
    mv -- "$f" "${f%.keep.$1}"
done

Alternatively, here is a solution using find and a while read loop (assumes GNU or BSD find):

find . -type f -name "*.keep.$1" -print0 | while IFS= read -r -d '' f; do
    mv -- "$f" "${f%.keep.$1}"
done

See http://mywiki.wooledge.org/BashFAQ/030 for more details on this solution.

Also, you can implement what you are trying to do using find with -exec :

find . -type f -name "*.keep.$1" -exec sh -c 'mv -- "$2" "${2%.keep.$1}"' _ "$1" {} ';'

How about this?

[spatel@us tmp]$ x=aa.bb.cc
[spatel@us tmp]$ y=${x%.cc}
[spatel@us tmp]$ echo $y
aa.bb


[spatel@us tmp]$ x=aa.bb.cc
[spatel@us tmp]$ y=${x%.bb.cc}
[spatel@us tmp]$ echo $y
aa

Shorter:

shopt -s globstar
rename 's/\.keep\.apple$//' **/*.keep.apple

(require perl)

If you can simply glob the files, you can do just

rename '.keep.apple' '' *

otherwise you would replace the * with the find + xargs you already have.

Note in this by rename is meant rename from util-linux . On some systems it is installed like rename.ul instead of rename .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM