IFS和命令替换

问题描述 投票:1回答:4

我正在编写一个shell脚本来读取输入csv文件并相应地运行一个java程序。

#!/usr/bin/ksh
CSV_FILE=${1}
myScript="/usr/bin/java -version"
while read row
do
     $myScript
     IFS=$"|"
     for column in $row
     do 
        $myScript
     done
done < $CSV_FILE

csv文件:

a|b|c

有趣的是,for循环之外的$ myScript可以工作,但for循环中的$ myScript说“/ usr / bin / java -version:找不到[没有这样的文件或目录]”。我知道这是因为我正在设置IFS。如果我评论IFS,并将csv文件更改为

a b c

有用 !我想shell使用默认的IFS来分隔命令/ usr / bin / java,然后再应用-version参数。由于我改变了IFS,它将整个字符串作为单个命令 - 或者我认为正在发生这种情况。

但这是我的要求:我有一个带有自定义分隔符的csv文件,该命令中包含参数,用空格分隔。我该怎么做才能正确?

linux shell ksh ifs command-substitution
4个回答
1
投票

IFS表示如何在不带引号的替换中拆分变量的值。它适用于$row$myscript

如果你想使用IFS进行拆分,这在普通的sh中很方便,那么你需要改变IFS的值或者安排需要相同的值。在这种特殊情况下,通过将myScript定义为myScript="/usr/bin/java|-version",您可以轻松地安排需要相同的值。或者,您可以及时更改IFS的值。在这两种情况下,请注意,不带引号的替换不仅仅使用IFS拆分值,它还将每个部分解释为通配符模式,并将其替换为匹配文件名列表(如果有)。这意味着,如果您的CSV文件包含类似的行

foo|*|bar

然后行不会是foo*barfoo,当前目录中的每个文件名,bar。要处理这样的数据,您需要使用set -f关闭。还要记住,当一行以反斜杠结尾时,read会读取延续行,并删除前导和尾随IFS字符。使用IFS= read -r关闭这两个行为。

myScript="/usr/bin/java -version"
set -f
while IFS= read -r row
do
    $myScript
    IFS='|'
    for column in $row
    do 
        IFS=' '
        $myScript
    done
done

然而,有更好的方法可以完全避免IFS分裂。不要将命令存储在以空格分隔的字符串中:它在复杂情况下失败,例如需要包含空格的参数的命令。存储命令有三种可靠的方法:

  • 将命令存储在函数中。这是最自然的方法。运行命令是代码;你在函数中定义代码。您可以将函数的参数统称为"$@"myScript () { /usr/bin/java -version "$@" } … myScript extra_argument_1 extra_argument_2
  • 将可执行命令名及其参数存储在数组中。 myScript=(/usr/bin/java -version) … "${myScript[@]}" extra_argument_1 extra_argument_2
  • 存储一个shell命令,即shell要解析的东西。要评估字符串中的shell代码,请使用eval。一定要引用参数,就像任何其他变量扩展一样,以避免过早的通配符扩展。这种方法更复杂,因为它需要仔细引用。当您必须将命令存储在字符串中时,它才真正有用,例如,因为它作为脚本的参数出现。请注意,您不能以这种方式明智地传递额外的参数。 myScript='/usr/bin/java -version' … eval "$myScript"

此外,由于您使用的是ksh而不是普通sh,因此您无需使用IFS来分割输入行。使用read -A代替直接拆分成数组。

#!/usr/bin/ksh
CSV_FILE=${1}
myScript=(/usr/bin/java -version)
while IFS='|' read -r -A columns
do
    "${myScript[@]}"
    for column in "${columns[@]}"
    do 
        "${myScript[@]}"
    done
done <"$CSV_FILE"

0
投票

IFS告诉shell哪些字符分隔“单词”,即命令的不同组成部分。所以当你从IFS中删除空格字符并运行foo bar时,脚本会看到一个参数“foo bar”而不是“foo”和“bar”。


0
投票

最简单的灵魂是避免改变qazxsw poi并与qazxsw poi进行分裂,如下所示:

IFS

-1
投票

IFS应该放在“while”的后面

read -d <delimiter>
© www.soinside.com 2019 - 2024. All rights reserved.