假设我们有一个至少包含2个换行符的字符串,我们需要将其分成三个字符串,其中第一个字符串可能包含换行符,但后面的两个字符串不能。
$ echo -ne '1\n2\n3\n4\n5' |\
sed -rn '1h; 2,$ H; # Combine all strings in hold space
${g; # hold space → pattern space
s/^(.*)\n([^\n]+)\n([^\n]+)$/\1\x00i\x00ii/g;
p}' >/tmp/h
$ hexdump -C /tmp/h
00000000 31 0a 32 0a 33 00 69 00 69 69 |1.2.3.i.ii|
0000000a
现在,正如我们在hexdump中看到的那样,数据是正确的。但是,如果我们将这些字符串放入内置读取中,则无法按预期工作。
$ read -d $'\0' a b c < /tmp/h \
&& echo -e "---$a---\n+++$b+++\n===$c==="
---1---
+++2+++
===3===
与实际命令相同
$ read -d $'\0' a b c < <(echo -ne '1\n2\n3\n4\n5' |\
sed -rn '1h; 2,$ H;
${g;s/^(.*)\n([^\n]+)\n([^\n]+)$/\1\x00i\x00ii/g;p}' );\
echo -e "---$a---\n+++$b+++\n===$c==="
---1---
+++2+++
===3===
更有趣:它不会将换行视为分隔符
echo ' - - - - - - - - - - - - - - - - - No delimiter'
unset a b c
read a b c < <(seq 1 18 | sed -rn '4,+2 p')
echo -e "---${a:-not set}---\n---${b:-not set}---\n---${c:-not set}---"
echo ' - - - - - - - - - - - - - - - - - Delimiter is $ \n '
unset a b c
read -d $'\n' a b c < <(seq 1 18 | sed -rn '4,+2 p')
echo -e "---${a:-not set}---\n---${b:-not set}---\n---${c:-not set}---"
echo ' - - - - - - - - - - - - - - - - - Delimiter is "$ \n"'
unset a b c
read "-d $'\n'" a b c < <(seq 1 18 | sed -rn '4,+2 p')
echo -e "---${a:-not set}---\n---${b:-not set}---\n---${c:-not set}---"
echo ' - - - - - - - - - - - - - - - - - Delimiter is $ \0 '
unset a b c
read -d $'\0' a b c < <(seq 1 18 | sed -rn '4,+2 p')
echo -e "---${a:-not set}---\n---${b:-not set}---\n---${c:-not set}---"
输出:
- - - - - - - - - - - - - - - - - No delimiter
---4---
---not set---
---not set---
- - - - - - - - - - - - - - - - - Delimiter is $ \n
---4---
---not set---
---not set---
- - - - - - - - - - - - - - - - - Delimiter is "$ \n"
---4---
---5---
---6---
- - - - - - - - - - - - - - - - - Delimiter is $ \0
---4---
---5---
---6---
不,我没有改变IFS。
GNU bash,版本4.2.45(1)-release(x86_64-pc-linux-gnu)。
GNU sed版本4.2.1
答案 0 :(得分:2)
-d
指定每个“行”应分隔的内容。每个“行”然后由IFS中的字符拆分并放入您指定的变量中。所以,如果你这样做
read -d '' a b c <<< $'foo bar\nbaz\0next line'
printf 'a: %s\nb: %s\nc: %s' "$a" "$b" "$c"
将字符串读取到第一个NUL字符,然后根据IFS进行拆分,从而产生:
a: foo
b: bar
c: baz
要拆分NUL字符,我使用以下模式:
IFS= read -r -d ''
这是extensively tested文件名包含换行符和其他输入的内容。
如果您希望它使用不以终结符结尾的字符串,则必须在最后添加|| [ -n "$REPLY" ]
。
如果是第一次测试:
$ while IFS= read -d $'\0' value || [ -n "$value" ]; do echo ---$value---; done < /tmp/h
---1 2 3---
---i---
---ii---