Dave Jarvis Dave Jarvis - 3 months ago 9
Bash Question

Suppress Keyword Expansion in Shell Script

Background



A shell script generates a number of Java source files. The source files have a particular header comment that includes Subversion keywords. The goal is to check-in the shell script without changing the source file headers buried within.

Problem



The shell script contains its own header, which should have keyword expansion:

#!/bin/bash
#
# Revision Control Information
# File: $Id:: autogenerate.sh 3142 2016-08-26 18:50:21Z USERNA#$
# Date of Last Commit: $Date:: 2016-08-26 11:50:21 -0700 (Fri, 26 Aug 2016) $
# Revision Number: $Rev:: 3142 $
# Last Commit by: $Author:: USERNAME $


This part works. The part that fails is when a comment is included later on in the shell script:

cat <<EOT >> $FILENAME_IMPL
/*
* *********************************************************************
* Revision Control Information
* File: $Id:: $
* Date of Last Commit: $Date:: $
* Revision Number: $Rev:: $
* Last Commit by: $Author:: $
*
* **********************************************************************
*/
package com.company.pkg;
EOT


When checking the shell script into the repository, the first set of keywords are expanded correctly; however, the keywords for the Java comment header are also expanded. I had thought that once a keyword was expanded, subsequent matches of the same keyword would be ignored. This is not the case.

Checking into the repository changes the comment that will be added to the top of every Java source file:

cat <<EOT >> $FILENAME_IMPL
/*
* *********************************************************************
* Revision Control Information
* File: $Id:: autogenerate.sh $
* Date of Last Commit: $Date:: 2016-08-26 11:50:21 -0700 (Fri, 26 Aug 2016) $
* Revision Number: $Rev:: 1234 $
* Last Commit by: $Author:: USERNAME $
*
* **********************************************************************
*/
package com.company.pkg;
EOT


The filename for the Java source won't be "autogenerate.sh", but rather "ClassName.java".

Clarification



To clarify, consider the following simple shell script called
autogenerate.sh
:

#!/bin/bash
# File: $Id:: $

FILENAME_IMPL=ClassName.java

cat <<EOT >> $FILENAME_IMPL
/* File: $Id:: $
*/
package com.company.pkg;
EOT


When the script is checked into the repository, its contents become:

#!/bin/bash
# File: $Id:: autogenerate.sh $

FILENAME_IMPL=ClassName.java

cat <<EOT >> $FILENAME_IMPL
/* File: $Id:: autogenerate.sh $
*/
package com.company.pkg;
EOT


The first
$Id::
keyword is correctly substituted. The second
$Id::
keyword should be ignored. In other words, when I check the script into the repository, I'd like to see:

#!/bin/bash
# File: $Id:: autogenerate.sh $

FILENAME_IMPL=ClassName.java

cat <<EOT >> $FILENAME_IMPL
/* File: $Id:: $
*/
package com.company.pkg;
EOT


Ideas



Escaping the keyword did not help. For example:

cat <<EOT >> $FILENAME_IMPL
/* File: \$Id:: $
*/
package com.company.pkg;
EOT


Question



How would you prevent or suppress keyword expansion for all but the first matching keyword when checking into a Subversion repository?

Answer

Try:

xId='$Id'; xDate='$Date'; xRev='$Rev'; xAuthor='$Author'
cat <<EOT >> "$FILENAME_IMPL"
/*
 * *********************************************************************
 *  Revision Control Information
 *  File:                $xId::                                         $
 *  Date of Last Commit: $xDate::                                       $
 *  Revision Number:     $xRev::                                        $
 *  Last Commit by:      $xAuthor::                                     $
 *
 * **********************************************************************
 */
package com.company.pkg;
EOT

This, by the way, fixes another problem: in the original code, $Id, $Date, and the others were expanded by the shell before they were written to $FILENAME_IMPL. With this code, the output in $FILENAME_IMPL will be what you expect.