[英]IFS and command substitution
我正在編寫一個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
有用 ! 我想象外殼使用默認的IFS來分隔命令/ usr / bin / java,然后在以后應用-version參數。 自從我更改了IFS之后,它就將整個字符串作為單個命令-或我認為正在發生的事情。
但這是我的要求:我有一個帶有自定義定界符的csv文件,並且命令中包含參數,並用空格分隔。 如何正確執行此操作?
IFS
指示如何在無引號的替換中拆分變量的值。 它適用於$row
和$myscript
。
如果要使用IFS
進行拆分(這在普通sh中很方便),則需要更改IFS
的值或安排需要相同的值。 在這種特殊情況下,通過將myScript
定義為myScript="/usr/bin/java|-version"
,您可以輕松安排需要相同的值。 或者,您可以及時更改IFS
的值。 在這兩種情況下,請注意,不帶引號的替換不僅會使用IFS
拆分值,還會將每個部分解釋為通配符模式,並用匹配文件名列表(如果有)替換它。 這意味着,如果您的CSV文件包含以下行
foo|*|bar
那么該行將不是foo
, *
, bar
而是foo
(當前目錄中每個文件名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解析的命令 。 要評估字符串中的外殼代碼,請使用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"
IFS
告訴外殼程序哪些字符分隔“單詞”,即命令的不同組成部分。 因此,當您從IFS
刪除空格字符並運行foo bar
,腳本會看到單個參數 “ foo bar”,而不是“ foo”和“ bar”。
最簡單的選擇是避免更改IFS
並使用read -d <delimiter>
進行拆分,如下所示:
#!/usr/bin/ksh
CSV_FILE=${1}
myScript="/usr/bin/java -version"
while read -A -d '|' columns
do
$myScript
for column in "${columns[@]}"
do
echo next is "$column"
$myScript
done
done < $CSV_FILE
IFS應該放在“ while”后面
#!/usr/bin/ksh
CSV_FILE=${1}
myScript="/usr/bin/java -version"
while IFS="|" read row
do
$myScript
for column in $row
do
$myScript
done
done < $CSV_FILE
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.