Linux脚本文件名中的空格

时间:2017-09-08 16:28:24

标签: linux bash shell scripting whitespace

我目前正在使用供应商提供的软件,该软件试图将附件文件发送到另一个脚本,该脚本将从列出的文件中进行文本提取。当我们从包含空格的外部源接收文件时脚本失败,因为供应商提供的软件没有用引号括起文件名 - 这意味着当运行文本提取脚本时,它会收到一个文件名,该文件将在空格上分开并在提取器脚本上导致错误。供应商提供的软件不可由我们编辑。

整个过程设计为自动转换,因此使用这种可能随机丢入齿轮的扳手是一个问题。

我们要做的是在文本提取器脚本中处理间隔名称,因为这是我们可以控制的部分。快速谷歌之后,似乎更改脚本的IFS值将是快速解决方案,但不幸的是,该脚本将在扩展已经残缺传入数据后生效。

我正在使用的脚本包含-e值,-i值和-o值。这些值是从供应商提供的脚本发送的,我没有编辑控制权。

#!/bin/bash

usage() { echo "Usage: $0 -i input -o output -e encoding" 1>&2; exit 1; }

while getopts ":o:i:e:" o; do
    case "${o}" in
        i)
            inputfile=${OPTARG}
            ;;
        o)
            outputfile=${OPTARG}
            ;;
        e)
            encoding=${OPTARG}
            ;;
        *)
            usage
            ;;
    esac
done
shift $((OPTIND-1))

...
...
<Uses the inputfile, outputfile, and encoding variables>

我承认,可能有些内容我不完全理解,它可能是一个简单的修复,但我的最终目标是能够提取所有包含1的-o,-i和-e值,不管每个部分内的空格。我可以在提取文件名值

后处理引用脚本

3 个答案:

答案 0 :(得分:3)

您发布的脚本片段与参数中的空格没有任何问题。

例如,以下内容不需要引用(因为它是一项任务):

inputfile=${OPTARG}

脚本$inputfile的所有其他用法都应加双引号

重要的是如何调用此脚本。

这会失败,只会将hello分配给变量inputfile

$ ./script.sh -i hello world.txt

字符串world.txt将提示getopts函数停止处理命令行,脚本将继续shiftworld.txt将保留在{{1}之后)。

以下内容会将字符串$1正确分配给hello world.txt

inputfile

就像

一样
$ ./script.sh -i "hello world.txt"

答案 1 :(得分:1)

以下脚本使用awk拆分参数,同时在文件名中包含空格。参数可以是任何顺序。它不处理参数中的多个连续空格,它将它们折叠为一个。

#!/bin/bash

IFS=' '
str=$(printf "%s" "$*")

istr=$(echo "${str}" | awk 'BEGIN {FS="-i"} {print $2}' | awk 'BEGIN {FS="-o"} {print $1}' | awk 'BEGIN {FS="-e"} {print $1}')
estr=$(echo "${str}" | awk 'BEGIN {FS="-e"} {print $2}' | awk 'BEGIN {FS="-o"} {print $1}' | awk 'BEGIN {FS="-i"} {print $1}')
ostr=$(echo "${str}" | awk 'BEGIN {FS="-o"} {print $2}' | awk 'BEGIN {FS="-e"} {print $1}' | awk 'BEGIN {FS="-i"} {print $1}')

inputfile=""${istr}""
outputfile=""${ostr}""
encoding=""${estr}""

# call the jar

调用jar时出现问题,其中Java在带有空格的文件名上抛出MalformedUrlException。

答案 2 :(得分:1)

因此,在阅读评论后,我们认为尽管对于每个场景可能都不是正确答案,但这个特定场景的正确答案是手动提取部分。

因为我们正在为传递给它的预构建脚本构建它,并且我们不会很快更新该脚本,所以我们可以肯定地接受这个脚本将始终接收-i,-o和 - e标志,它们之间会有空格,这会导致传入的所有部分存储在$*的不同变量中。

我们可以假设标志后面的文本是对标志的响应,直到引用另一个标志。这留下了3个场景:

  1. 该变量包含其中一个标志
  2. 变量包含紧跟在标志
  3. 之后的第一个参数
  4. 变量包含参数的第2部分,名称中的空格被解释为拆分,需要重新插入。
  5. 我一直遇到的其他问题之一就是尝试将字符串文字等同于我的IF语句中的变量。为了解决这个问题,我在数组变量中预先存储了所有相关数据,因此我可以测试$ variable == $ otherVariable。

    虽然我不希望它改变,但如果三个标志的出现顺序与我们预期的不同,我们也会处理该怎么做(我们的假设是它们列为i,o,e ......但我们可以不要惊讶地看到通过的是什么。参数按读入顺序转储到数组中,并行数组跟踪插槽0,1,2中的项是否与i,o,e相关。

    最终结果仍有一个缺陷:如果文件名中有多个连续的空格,则在处理之前修剪空白,我只能占一个空格。但是当我们在遇到一个带有空格的文件之前处理超过4000个文件时,我发现不太可能使用命名约定我们会遇到多个空格。

    此时,无论如何我们都必须踩到一个罕见的干预。

    最终的代码更改如下:

    #!/bin/bash
    IFS='|'
    
    position=-1
    ioeArray=("" "" "")
    previous=""
    flagArr=("-i" "-o" "-e" " ")
    ioePattern=(0 1 2)
    
    
    #echo "for loop:"
    for i in $*; do
        #printf "%s\n" "$i"
        if [ "$i" == "${flagArr[0]}" ] || [ "$i" == "${flagArr[1]}" ] || [ "$i" == "${flagArr[2]}" ]; then
            ((position += 1));
            previous=$i;
            case "$i" in
                "${flagArr[0]}")
                ioePattern[$position]=0
                ;;
                "${flagArr[1]}")
                ioePattern[$position]=1
                ;;
                "${flagArr[2]}")
                        ioePattern[$position]=2
                ;;
            esac
            continue;
        fi
        if [[ $previous == "-"* ]]; then
            ioeArray[$position]=${ioeArray[$position]}$i;
        else
            ioeArray[$position]=${ioeArray[$position]}" "$i;
        fi
        previous=$i;
    
    done
    
    
    echo "extracting (${ioeArray[${ioePattern[0]}]}) to (${ioeArray[${ioePattern[1]}]}) with (${ioeArray[${ioePattern[2]}]}) encoding."
    
    inputfile=""${ioeArray[${ioePattern[0]}]}"";
    outputfile=""${ioeArray[${ioePattern[1]}]}"";
    encoding=""${ioeArray[${ioePattern[2]}]}"";