是否可以「保護」 IFS 字元免於字段拆分?

是否可以「保護」 IFS 字元免於字段拆分?

在 POSIX sh 或 Bourne shell(如 Solaris 10 中/bin/sh)中,是否可能有類似以下內容:

a='some var with spaces and a special space'
printf "%s\n" $a

並且,使用預設值IFS,得到:

some
var
with
spaces
and
a
special space

也就是說,透過引用或轉義的某種組合來保護special和之間的空格?space

a事先不知道其中的字數,否則我會嘗試以下操作:

a='some var with spaces and a special\ space'
printf "%s\n" "$a" | while read field1 field2 ...

上下文是這個錯誤Cassandra 中報告,OP 嘗試設定一個環境變數來指定 JVM 的選項:

export JVM_EXTRA_OPTS='-XX:OnOutOfMemoryError="echo oh_no"'

在執行 Cassandra 的腳本中,它必須支援 POSIX sh 和 Solaris sh:

JVM_OPTS="$JVM_OPTS $JVM_EXTRA_OPTS"
#...
exec $NUMACTL "$JAVA" $JVM_OPTS $cassandra_parms -cp "$CLASSPATH" $props "$class"

IMO 唯一的出路是使用包裝指令的腳本echo oh_no。還有別的辦法嗎?

答案1

並不真地。

一種解決方案是保留一個字元作為字段分隔符號。顯然,無論該角色是什麼,都不可能包含在選項中。如果來源語言可以輕鬆插入製表符和換行符,那麼它們就是明顯的候選者。如果您想要可移植性,我會避免使用多位元組字元(例如 dash 和 BusyBox 不支援多位元組字元)。

如果您依賴 IFS 分割,請不要忘記使用 關閉通配符擴充set -f

tab=$(printf '\t')
IFS=$tab
set -f
exec java $JVM_EXTRA_OPTS …

另一種方法是引入引用語法。一個非常常見的引用語法是反斜線保護下一個字元。使用反斜杠的缺點是,許多不同的工具將其用作引用字符,有時很難確定需要多少個反斜杠。

set java
eval 'set -- "$@"' $(printf '%s\n' "$JVM_EXTRA_OPTS" | sed -e 's/[^ ]/\\&/g' -e 's/\\\\/\\/g') …
exec "$@"

答案2

如果您使用的是 Bash 或類似的工具,數組就可以解決問題:

a=(some var with spaces and a 'special space')

但由於 POSIX shell 沒有這些,我能看到的最好的內部方法是實際使用一個特殊的空間。不間斷空格 (U+00A0) 非常適合此目的,但在 ASCII 之外需要就腳本的字元集達成一致。

a="some var with spaces and a special space"
# this is a non-breaking space ------^
echo "$a" \
| while read word; do printf '%s\n' ${word} | sed 's@ @ @g'; done
# this is a non-breaking space ----------------------^

這輸出:

some
var
with
spaces
and
a
special space

目前,我不確定如何將其包含在變數擴展中(它將需要一個子 shell),但這應該為進一步調查提供一個起點。

相關內容