Shell脚本使用参数调用Jar - 被视为一个String的文件名列表

时间:2014-04-25 09:40:23

标签: bash shell

我有一个用于自动部署文件的java应用程序。 我想创建一个shell脚本,以便从svn轻松部署。

目前,我的脚本检出文件,获取文件名,询问一些部署信息,然后将文件名传递给Jar。

通常,我可以在-f选项之后传递多个文件,并且Jar收集每个文件,如果文件存在,则将它们添加到数组中进行处理。如果文件名包含空格,我会在文件名周围添加引号。

这是通常与我的Jar一起使用的输入:

java -jar deploy.jar -f 'Cancellation V2.xsl' 'Final Price.xsl' -e test

我的shell脚本从SVN url的末尾获取文件名,在名称周围添加引号并传递给Jar。我收到这个错误:

'Final Price.xsl' 'Cancellation V2.xsl'  not found!
 Exception in thread "main" com.DeployException: 
     at com.ConsoleUtils.parseCommandLineArgs(ConsoleUtils.java:42)
     at com.Main.main(Main.java:23)

当Java应用程序在将每个文件名添加到数组之前使用if(file.exists)之前,会抛出此异常。此日志显示两个文件名都作为单个字符串传递,即使shell脚本已正确格式化它们。

这是我的完整Shell脚本:

#!/bin/bash
now=`date +%Y%m%d%H%M`
mkdir 'deployment-'$now
cd 'deployment-'$now

echo 'Please type tag name to deploy from:'
   read tag

#svn export svn://------[removed]------
#This checks out a list of SVN urls to deploy.

j=1
for i in `cat deploy-filelist`
do
   filename=$i
   $j = $j++
   svn export $filename
   echo $filename | rev | cut -d/ -f1 | rev >> files.txt
done

echo 'loaded' $j 'files'

#svn export svn://------[removed]------
#This checks out the Jar used to deploy the files

files=''
for f in `cat files.txt`
do
   filename="${f/\%20/ }"
   files+="'$filename' "
done

echo $files >> files.txt

echo "Please type environment to deploy to [devl | test | etc]:"
  read env

java -jar deploy.jar -f "$files" -e $env

有人能就处理文件名给我一些建议吗?当相同的格式通常正常时,为什么变量读为一个String?

其他意见得到了回应。

感谢您阅读

4 个答案:

答案 0 :(得分:2)

代码的最后一行显示“$ files”,这意味着对字符串执行以下操作:

"'filename1' 'filename2'"

因此,它由JVM读取为一个字符串,并作为单个参数传递。

要解决此问题,请删除$ file周围的引号,如Mubin所暗示的那样。

进一步提示,尝试在Shell的不同阶段回显您的输出,以便您可以看到整个程序中变量发生了什么。在调试Shell时大量帮助。

答案 1 :(得分:2)

"经典"真的不是一个好方法。 Bourne shell引用内部引号的东西并稍后插入它。由于您在shebang线上使用Bash,简单而直接的解决方法是将文件名列表放在数组中。

IFS=$'\n' urls=($(cat deploy-filelist))
for u in "${urls[@]}"; do
    svn export "$u"
done
echo "Exported ${#urls[@]} files"

IFS=$'\n' basenames=($(sed 's%.*/%%;s/%20/ /g' deploy-filelist))

请注意这会如何消除您编写和重写files.txt文件时遇到的一些相当折磨的shell脚本,我认为您不需要其他任何内容(将其作为副产品创建)如果因其他原因需要它,显然是微不足道的。)

(我将数组重命名为urlsbasenames以保持其自我记录和唯一性。第一个显然包含SVN repo URL,而第二个只包含非目录部分,任意{ {1}}归一化回空间。)

现在您可以插入数组,并保留引号,例如

%20

(这对我来说看起来仍然有点滑稽。java -jar deploy.jar -f "${basenames[@]}" -e $env 选项是布尔值,你提供两个文件名,或者是-f一个需要文件名参数的选项,你应该有两个他们?)

答案 2 :(得分:1)

问题从这里开始:

`for f in `cat files.txt`

你可能会认为每行会给你一个f,但不会,每个单词会给你一个f。因此,如果您的文件有空格,它将拆分它们。

您可以将其替换为:

cat files.txt | while read -r
do
    f="$REPLY"
    # rest of your code here
done

然后仍然在jar调用行中删除双引号。

read命令将从stdin中读取每一行,我们在这里输出文件列表,每行一个,并将其存储在$REPLY变量中。它不会像for那样分割单词。

答案 3 :(得分:1)

快速重写,结合了大部分给定的建议,添加了一些我自己的建议:

#!/bin/bash
dir=deployment-$(date +%Y%m%d%H%M)
mkdir "$dir" || { echo "could not mkdir $dir"; exit 1; }
cd "$dir"

read -p 'Please type tag name to deploy from: ' tag

#svn export svn://------[removed]------
#This checks out a list of SVN urls to deploy.

j=1
files=()
while read -r filename; do
    if [[ -f "$filename" ]]; then
        ((j++))
        svn export "$filename"
        files+=( "$(basename "$filename")" )
    else
        echo "warning: no such file: $filename"
    fi
done < deploy-filelist

echo "loaded $j files"
echo ${files[@]}" >> files.txt

#svn export svn://------[removed]------
#This checks out the Jar used to deploy the files

while :; do
    read -p "Please type environment to deploy to [devl | test | etc]: " env
    case $env in
        devl|test|etc) break ;;
    esac
done

java -jar deploy.jar -f "${files[@]}" -e $env