Chine Gary Chine Gary - 1 month ago 12
Bash Question

String concatenating error in shell script executing

This is a wired problem confusing me for days.I want to get a class's full class name from parse the java code file in shell.We can get package name from like:

package com.android.mail.ui;

and get class name from code file path,use shell command 'basename'.
below is my shell scripts:

#!/bin/bash
get_package_name(){
java_file=$1
if [ ! -f $file_path ]; then
echo "Sorry,the java file is not exist:$1,please check"
exit 1
fi
class_base_name=`basename "$java_file" .java`
echo "class_base_name:$class_base_name"
package_name=`grep $java_file -e "^package" | awk -F " " '{print $2}' | tr ';' ' ' | sed 's/ //g'`
echo "package_name get result:$?"
echo "package_name:$package_name"


method 1,use variable concat directly



classpath_name=$package_name.$class_base_name
echo "method 1 classpath_name:$classpath_name"


method 2,use sed replace to get concat indirectly



classpath_name2=`echo "aa.bb" | sed "s/aa/$package_name/" | sed "s/bb/$class_base_name/"`
echo "method 2 classpath_name2:$classpath_name2"


}


The problem is:for some code file the result is ok,like:
"class_base_name:MailTransport package_name get result:0
package_name:com.android.email.mail.transport method 1
classpath_name:com.android.email.mail.transport.MailTransport method 2
classpath_name2:com.android.email.mail.transport.MailTransport"

for others it's output is : "class_base_name:EmailApplication
package_name get result:0 package_name:com.android.email
.EmailApplicationh_name:com.android.email
.EmailApplicationh_name2:com.android.email"

the result is totally messing and wrong.I doubt it relates the code
content,that really make sense for the result?

Answer

This happens because some of your files use Windows style CRLF (\r\n) line terminators.

Here's an example where it works, a normal Unix style LF (\n) terminated file:

$ file WorkingFile.java
WorkingFile.java: ASCII text

$ cat -v WorkingFile.java
package foo.bar.baz;

$ get_package_name WorkingFile.java
class_base_name:WorkingFile
package_name get result:0
package_name:foo.bar.baz
method 1 classpath_name:foo.bar.baz.WorkingFile

Here's an example where it fails, with CRLF line terminators:

$ file FailingFile.java
FailingFile.java: ASCII text, with CRLF line terminators

$ cat -v FailingFile.java
package foo.bar.baz;^M        <--- note hidden control char revealed by -v

$ get_package_name FailingFile.java
class_base_name:FailingFile
package_name get result:0
package_name:foo.bar.baz
.FailingFilesspath_name:foo.bar.baz

To fix it, you can delete the extra carriage returns using tr -d '\r'. I switched from legacy backticks to modern $() to avoid problems with backslashes:

package_name=$(grep $java_file -e "^package" | awk -F " " '{print $2}' | tr ';' ' ' | sed 's/ //g' | tr -d '\r')

For more information, see this relevant post.