Q1。字段拆分。
字段拆分与单词拆分一样吗?
是的,两者都指向同一个想法。
是否设置IFS=''
为null,也设置为空字符串?
是的,所有三个含义相同:不得执行字段/单词拆分。此外,这会影响印刷领域(如echo "$*"
)的所有字段将与没有空间并置。
问题3 :(部分a)未设置IFS。
在POSIX规范中,我阅读以下内容:
如果未设置IFS,则外壳的行为应类似于IFS的值为<space> <tab> <newline>。
完全等同于:
如果使用unset IFS
,则外壳将表现为默认IFS。
这意味着“字段拆分”将与默认的IFS值完全相同,或者未设置。
这并不意味着IFS在所有情况下都将以相同的方式工作。更具体地说,执行OldIFS=$IFS
会将var设置OldIFS
为null,而不是默认值。这样,尝试将IFS设置回去,IFS=OldIFS
会将IFS设置为null,而不是像以前一样将其保持为未设置状态。小心 !!。
问题3:(b部分)还原IFS。
如何将IFS的值恢复为默认值。说我想恢复IFS的默认值。我怎么做?(更具体地说,如何引用<tab>和<newline>?)
对于zsh,ksh和bash(AFAIK),IFS可以设置为默认值,例如:
IFS=$' \t\n' # works with zsh, ksh, bash.
完成后,您无需再阅读其他任何内容。
但是,如果需要为sh重新设置IFS,它可能会变得很复杂。
让我们从最简单的角度看一看,没有缺点(复杂度除外)。
1.-取消IFS。
我们可以unset IFS
(请参阅上面的Q3部分a)。
2.-交换字符。
作为一种解决方法,交换tab和换行符的值可使设置IFS的值更简单,然后以等效的方式工作。
将IFS设置为<space> <newline> <tab>:
sh -c 'IFS=$(echo " \n\t"); printf "%s" "$IFS"|xxd' # Works.
3.-简单吗?解:
如果存在需要正确设置IFS的子脚本,则始终可以手动编写:
IFS ='
'
手动键入的序列为:IFS=
'spacetabnewline',实际上已在上面正确键入的序列(如果需要确认,请编辑此答案)。但是从浏览器复制/粘贴将中断,因为浏览器将挤压/隐藏空白。很难共享上面编写的代码。
4.-完整的解决方案。
编写可以安全复制的代码通常涉及明确的可打印转义符。
我们需要一些“产生”期望值的代码。但是,即使在概念上正确,此代码也不会设置结尾\n
:
sh -c 'IFS=$(echo " \t\n"); printf "%s" "$IFS"|xxd' # wrong.
发生这种情况的原因是,在大多数shell下,扩展时会删除所有结尾的换行符$(...)
或`...`
命令替换。
我们需要对sh 使用技巧:
sh -c 'IFS="$(printf " \t\nx")"; IFS="${IFS%x}"; printf "$IFS"|xxd' # Correct.
另一种方法是将IFS设置为bash的环境值(例如),然后调用sh(接受通过环境设置的IFS的版本),如下所示:
env IFS=$' \t\n' sh -c 'printf "%s" "$IFS"|xxd'
简而言之,sh使将IFS重置为默认值是一件很奇怪的事情。
问题4:在实际代码中:
最后,这段代码将如何:
while IFS= read -r line
do
echo $line
done < /path_to_text_file
如果我们将第一行更改为
while read -r line # Use the default IFS value
或者:
while IFS=' ' read -r line
第一:我不知道echo $line
豚鼠上是否有(带有VAR NOT引号)。它引入了读取所没有的第二级“字段拆分”。所以我都会回答。:)
使用此代码(以便您可以确认)。您将需要有用的xxd:
#!/bin/ksh
# Correctly set IFS as described above.
defIFS="$(printf " \t\nx")"; defIFS="${defIFS%x}";
IFS="$defIFS"
printf "IFS value: "
printf "%s" "$IFS"| xxd -p
a=' bar baz quz '; l="${#a}"
printf "var value : %${l}s-" "$a" ; printf "%s\n" "$a" | xxd -p
printf "%s\n" "$a" | while IFS='x' read -r line; do
printf "IFS --x-- : %${l}s-" "$line" ;
printf "%s" "$line" |xxd -p; done;
printf 'Values quoted :\n' "" # With values quoted:
printf "%s\n" "$a" | while IFS='' read -r line; do
printf "IFS null quoted : %${l}s-" "$line" ;
printf "%s" "$line" |xxd -p; done;
printf "%s\n" "$a" | while IFS="$defIFS" read -r line; do
printf "IFS default quoted : %${l}s-" "$line" ;
printf "%s" "$line" |xxd -p; done;
unset IFS; printf "%s\n" "$a" | while read -r line; do
printf "IFS unset quoted : %${l}s-" "$line" ;
printf "%s" "$line" |xxd -p; done;
IFS="$defIFS" # set IFS back to default.
printf "%s\n" "$a" | while IFS=' ' read -r line; do
printf "IFS space quoted : %${l}s-" "$line" ;
printf "%s" "$line" |xxd -p; done;
printf '%s\n' "Values unquoted :" # Now with values unquoted:
printf "%s\n" "$a" | while IFS='x' read -r line; do
printf "IFS --x-- unquoted : "
printf "%s, " $line; printf "%s," $line |xxd -p; done
printf "%s\n" "$a" | while IFS='' read -r line; do
printf "IFS null unquoted : ";
printf "%s, " $line; printf "%s," $line |xxd -p; done
printf "%s\n" "$a" | while IFS="$defIFS" read -r line; do
printf "IFS defau unquoted : ";
printf "%s, " $line; printf "%s," $line |xxd -p; done
unset IFS; printf "%s\n" "$a" | while read -r line; do
printf "IFS unset unquoted : ";
printf "%s, " $line; printf "%s," $line |xxd -p; done
IFS="$defIFS" # set IFS back to default.
printf "%s\n" "$a" | while IFS=' ' read -r line; do
printf "IFS space unquoted : ";
printf "%s, " $line; printf "%s," $line |xxd -p; done
我得到:
$ ./stackexchange-Understanding-IFS.sh
IFS value: 20090a
var value : bar baz quz -20202062617220202062617a20202071757a2020200a
IFS --x-- : bar baz quz -20202062617220202062617a20202071757a202020
Values quoted :
IFS null quoted : bar baz quz -20202062617220202062617a20202071757a202020
IFS default quoted : bar baz quz-62617220202062617a20202071757a
IFS unset quoted : bar baz quz-62617220202062617a20202071757a
IFS space quoted : bar baz quz-62617220202062617a20202071757a
Values unquoted :
IFS --x-- unquoted : bar, baz, quz, 6261722c62617a2c71757a2c
IFS null unquoted : bar, baz, quz, 6261722c62617a2c71757a2c
IFS defau unquoted : bar, baz, quz, 6261722c62617a2c71757a2c
IFS unset unquoted : bar, baz, quz, 6261722c62617a2c71757a2c
IFS space unquoted : bar, baz, quz, 6261722c62617a2c71757a2c
第一个值只是的正确值 IFS=
'spacetabnewline'
下一行是var $a
具有的所有十六进制值,最后是换行符'0a',因为它将被赋予每个读取命令。
IFS为null的下一行不执行任何“字段拆分”,但是将换行符删除(按预期方式)。
接下来的三行,因为IFS包含空格,请删除初始空格,并将var行设置为剩余余额。
最后四行显示未引用的变量将执行的操作。这些值将在(几个)空格上分开,并打印为:bar,baz,qux,
IFS
和未设置值IFS
有很大不同。问题4的答案在某种程度上是错误的:这里没有触及内部分隔符,只有前导和尾随的分隔符。