1

Here is a small sample of the files I need to rename:

    ID_EDMSCP_20160815.txt.pgp
    ID_EDMSCP_20160816.txt.pgp
    ID_EDMSCP_20160817.txt.pgp
    ID_EDMSCP_20160818.txt.pgp       

I have created a script from someone else's question as follows:

    for file in ID_EDMSCP_*.txt.pgp
    do
        mv -i "${file}" "${file/-ID-/-SUBMIT_GO_ID-}"
    done

However, I am getting the following:

    mv: `ID_EDMSCP_20160815.txt.pgp' and `ID_EDMSCP_20160815.txt.pgp' are the same file

And nothing is being renamed. Am I missing something?

3 Answers3

6

mv -i "${file}" "${file/-ID-/-SUBMIT_GO_ID-}"

That string replacement tells it to replace -ID-, which doesn't occur in your source file names. I think you mean to say this instead:

mv -i "${file}" "${file/ID_/SUBMIT_GO_ID_}"

Another problem you might be having is that this is a ksh93 feature, also available in Bash and Zsh, but not in pure POSIX shells. If you're using #!/bin/sh at the top of the script, it will run under either a POSIX shell or a pre-POSIX Bourne shell interpreter on some systems, which won't understand that.

There are a bunch of alternatives if you cannot use this nonstandard feature of advanced shells:

sed

If you need this script to be portable to all Unix type systems, you could switch to sed for the replacement:

mv -i "$file" "$(echo $file | sed -e 's/^ID_/SUBMIT_GO_ID_/')"

That still requires at least a POSIX shell, due to the use of $() style command interpolation, but that's an easier "ask" than to expect an advanced shell everywhere.

If your script had to run on every Bourne type shell ever, you could switch to backtick style command interpolation, which can be tricky to get right if you have embedded spaces in the file names, but that doesn't seem to be the case here, according to your posted example. So, this should be equivalent to the prior option for your purposes:

mv -i "$file" `echo $file | sed -e s/^ID_/SUBMIT_GO_ID_/`

mmv

Another option is to install mmv, a program that doesn't ship installed on any Unix type system I know of, but which is usually packaged for it in the standard package repository. With mmv, you can replace your whole shell script loop with

$ mmv 'ID_*' 'SUBMIT_GO_ID_#1'

Note that there is no -i flag because mmv doesn't support asking for every rename. It does, however, pre-check all planned renames and try to detect problems before beginning work, so it may be close enough for your purposes.

rename

Still another option is the rename command, of which there are at least three variants in the wild. There are two forks of Larry Wall's Perl script of that name, one of which may be installed on your system already as part of your Perl distribution. Then there is the util-linux variant, often either installed instead of that version on Linux machines, or beside it. If you have both installed, the Perl-based one is probably called prename to avoid a conflict.

The main advantage of the Perl-based ones is that you can use Perl regular expressions, which are more powerful than the glob expressions supported by mmv or the POSIX regular expressions supported by sed. It doesn't matter much in this particular instance, however, because the task is trivial:

$ rename '^ID_' SUBMIT_GO_ID_ ID_EDMSCP_*.txt.pgp

The util-linux version is much less capable because although it calls its first parameter the "expression", it is neither a POSIX regular expression nor a Perl regular expression. It isn't even a glob expression: it's just a literal string. But as above, that limitation doesn't actually hamper us in this particular case:

$ rename ID_ SUBMIT_GO_ID_ ID_EDMSCP_*.txt.pgp

As with mmv, rename doesn't support the -i flag.

Plain Old Bourne Shell

All of that having been said, your particular case allows a much simpler solution because your input pattern appears at the tail end of the output pattern, so you can do it all in portable Bourne shell syntax:

for file in ID_EDMSCP_*.txt.pgp
do
    mv -i "$file" SUBMIT_GO_"$file"
done

I've left the complicated alternatives above because they are often necessary, since the internal mechanisms within the shell language are not always sufficient.

Warren Young
  • 72,032
  • It appears my issue was due to using "-" instead of "_" purely to my ignorance. I assumed the dash marks were part of the code, but now I see the corrections have been successful. Thank you. – kirby willis Aug 23 '16 at 15:40
2

Try this:

for file in ID_EDMSCP_*.txt.pgp
do
    mv -i "${file}" SUBMIT_GO_"${file}"
done
1

Under Linux, you can use the rename command. It's very limited but it's good enough for this simple use case: replace the first occurrence of a substring by a different string.

rename ID SUBMIT_GO_ID ID_EDMSCP_*.txt.pgp

On Debian and derivatives (Ubuntu, Mint, …), that command is called rename.ul. The rename command on these distributions is a different one with an incompatible syntax, also called prename. With that command you can do

prename 's/ID/SUBMIT_GO_ID/' ID_EDMSCP_*.txt.pgp