如何使用包含带空格的字符串的数组执行命令 linux

how to execute a command using array containing strings with spaces linux

关于 bash shell 数组,我已经被困在一个问题上几个小时了。

我正在使用从输入文件创建的字符串数组,使用 IFS=$'\n' 作为分隔符。

数组的每个索引可能包含多个由 space 分隔的单词。每个字符串代表 Options/Arguments 的组合,可用于执行另一个 shell 脚本。

我尝试将这些字符串提供给我使用以下语法的变体编写的另一个 shell 脚本:

    # Run the testcases, case by case
    for testcase in `cat $inputFile` ###"${testcases[@]}"
    #for ((i = 0; i < ${#testcases[@]}; i++))
            do
                    #testcase="${testcases[i]}"
                    # Print each case in inputFile
                    echo "${testcase}"

                    # Run the Archive Script, redirect output to /dev/null
                    ./archive.sh "${testcase}" > /dev/null

    # Respond to $# return value

done

您会注意到一些不同的变体,我曾用来循环遍历数组(或尝试通过直接从 cat.

的输出中直接读入局部变量来直接响应

最令人沮丧的是 echo 命令有效,并打印带有 spaces 的字符串。但是,当我的脚本尝试使用字符串执行时,第一个单词被作为一个整体读取,但在第一个 space 之后,脚本尝试一次执行一个字符。 :(

请帮忙!这是我在执行脚本时得到的输出:

$ test_archive.sh lab6_testcase
Testcases Count: 6
Running cases:
-v dirA
./archive.sh: illegal option --  
./archive.sh: illegal option -- d
./archive.sh: illegal option -- i
./archive.sh: illegal option -- r
./archive.sh: illegal option -- A
dirB
-v -r dirA
./archive.sh: illegal option --  
./archive.sh: illegal option -- -
./archive.sh: illegal option -- r
./archive.sh: illegal option --  
./archive.sh: illegal option -- d
./archive.sh: illegal option -- i
./archive.sh: illegal option -- r
./archive.sh: illegal option -- A
-v dirA dirB
./archive.sh: illegal option --  
./archive.sh: illegal option -- d
./archive.sh: illegal option -- i
./archive.sh: illegal option -- r
./archive.sh: illegal option -- A
./archive.sh: illegal option --  
./archive.sh: illegal option -- d
./archive.sh: illegal option -- i
./archive.sh: illegal option -- r
./archive.sh: illegal option -- B
dirc
-a
./archive.sh: illegal option -- a
TEST SUMMARY
SUCCESSFUL CASES:0
USAGE CASES:0
INVALID ARGUMENT CASES:6
-v dirA
dirB
-v -r dirA
-v dirA dirB
dirc
-a

这是完整的脚本,以防我错过了一些关键行触发和错误:

#!/bin/bash
# CONSTANTS
SUCCESS=0
USAGE_ERROR=1
INVALID_ARGUMENT=2

# Set the Input Field Seperator to '\n'
IFS=$'\n'

# Setup counters
usageErrorCount=0
argumentErrorCount=0
successCount=0

# Check if not enough or too many arguments have bee supplied
if (( $# != 1 ))
then
   echo Usage: [=13=] filename
   exit $USAGE_ERROR
fi

# Store the File in inputFile
inputFile=

# Check if the inputFile exists
if [[ ! -f $inputFile ]]
then
        # Report that the file does not exist
        echo "Exiting: The input file '$inputFile' does not exist!"
        exit $INVALID_ARGUMENT
fi

# Read the lines from the file, and place them in the array
testcases=( `cat $inputFile` )

echo Testcases Count: ${#testcases[@]}


# Inform use of case list
echo Running cases:

# Run the testcases, case by case
for testcase in `cat $inputFile` ###"${testcases[@]}"
#for ((i = 0; i < ${#testcases[@]}; i++))
        do
                #testcase="${testcases[i]}"
                # Print each case in inputFile
                echo "${testcase}"

                # Run the Archive Script, redirect output to /dev/null
                ./archive.sh "${testcase}" > /dev/null

                # Use Switch Statement on ENV Success Var (#?) to:
                        # 1. Increment counters
                        # 2. Add testcase to appropriate array
                case $? in
                        $USAGE_ERROR)           # Add testcase to usage array
                                                                usageCases[$usageErrorCount]="$testcase"
                                                                # Up Usage Count
                                                                usageErrorCount=$((usageErrorCount+1))

                        ;;
                        $INVALID_ARGUMENT)      # Add testcase to argument array
                                                                argumentCases[$argumentErrorCount]="$testcase"
                                                                # Up Argument Count
                                                                argumentErrorCount=$((argumentErrorCount+1))

                        ;;
                        $INVALID_ARGUMENT)      # Add testcase to success array
                                                                successCases[$successCount]="$testcase"
                                                                # Up Success Count
                                                                successCount=$(($successCount+1))
                        ;;
                        esac
        done

# Format the Output
echo "TEST SUMMARY"

# Report Successful Cases
echo "SUCCESSFUL CASES:$successCount"
for testcase in  ${successCases[@]}
        do
                echo $testcase
        done

# Report Ussage Cases
echo "USAGE CASES:$usageErrorCount"
for testcase in  ${usageCases[@]}
        do
                echo $testcase
        done

# Report Successful Cases
echo "INVALID ARGUMENT CASES:$argumentErrorCount"
for testcase in  ${argumentCases[@]}
        do
                echo $testcase
        done

# Exit with Success
exit $SUCCESS
 ./archive.sh "${testcase}"

您正在使用单个参数调用 archive.sh(嵌入白色 space)。这就是双引号的作用。双引号内的所有内容都是一个单词。

由于参数的第一个字符是破折号,archive.sh 将参数的其余部分(包括嵌入的 space)作为选项,并抱怨它们不是有效选项。

您想删除引号。 Demo.

问题是由于您的 IFS 仍设置为 $'\n',因此 ./archive.sh 将整行作为单个参数读取并试图理解字母。

将 IFS 改回 ' ',问题应该消失了!

示例:

    # Run the testcases, case by case
    for testcase in "${testcases[@]}"
            do
                    IFS=' '
                    echo "${testcase}"

                    ./archive.sh "${testcase}" > /dev/null

done

经过一番挖掘,我找到了解决问题的方法。

问题是 shell 在 evaluating/dereferencing 变量(或数组值)的内容之前执行命令。

因此,必须使用 eval 强制 shell 取消引用 variable/array 并在执行 variable/array 的命令之前检索内容。

这是一个工作版本(直接从文件中读取):

for testcase in `cat $inputFile`
        do
                #testcase="${testcases[i]}"
                # Print each case in inputFile
                echo "  ${testcase}"

                # Run the Archive Script, redirect output to /dev/null
                eval ./lab5.sh ${testcase} > /dev/null

... CONTINUE WITH SCRIPT ...