这是我想要实现的行为示例:
假设我有一个行列表,每行包含空格分隔值:
lines='John Smith
James Johnson'
Run Code Online (Sandbox Code Playgroud)
而且我只想在用户通过提示询问时循环回显姓名或姓氏的行,因此我全局更改 IFS:
oIFS=$IFS
IFS='
'
for line in $lines; do
IFS=$oIFS
read name surname <<< $line
read -p "Do you want to echo name? surname otherwise "
if [[ $REPLY == "y" ]]; then
echo $name
else
echo $surname
fi
done
Run Code Online (Sandbox Code Playgroud)
这有效,但这种方法对我来说并不明智:
我发现while IFS=...可以像这样在这里使用:
while IFS='
' read line ; do
echo $line
read name surname <<< $line
read -p "Do you want to echo name? surname otherwise "
if [[ $REPLY == "y" ]]; then
echo $name
else
echo $surname
fi
done <<< "$lines"
Run Code Online (Sandbox Code Playgroud)
但这不是一个选项,因为read -p提示会被连续输入流破坏
一个解决方案是 IFS 只为这样的一个for语句设置:
IFS='
' for line in $lines; do
...
done
Run Code Online (Sandbox Code Playgroud)
但 bash 不允许这样做。
您可以先使用mapfile/将输入行读入数组readarray:
lines='John Smith
James Johnson'
mapfile -t lines <<< "$lines"
for line in "${lines[@]}"; do
read name surname <<< "$line"
echo "name: $name surname: $surname"
done
Run Code Online (Sandbox Code Playgroud)
如果lines来自某个命令的输出,您可以类似地mapfile -t lines < <(somecommand)直接使用。那里的进程替换有点像管道,但避免了在子壳中运行的管道部件的问题。请注意,您lines缺少最后一行末尾的换行符,但<<<添加了一个。mapfile不介意它是否丢失,但如果您在 末尾确实有换行符lines,您将获得一个空数组条目,用于额外的条目。使用进程替换可以绕过这个问题。
这里,
while IFS=... read line ; do
...
read -p "Do you want to echo name? surname otherwise "
done <<< "$lines"
Run Code Online (Sandbox Code Playgroud)
两者read确实从同一个输入读取,但我认为(没有测试)你可以通过重定向到循环使用另一个文件描述符来解决这个问题,例如:
while IFS=... read -u 3 line ; do
...
read -p "Do you want to echo name? surname otherwise "
done 3<<< "$lines"
Run Code Online (Sandbox Code Playgroud)
或者read <&3代替read -u,我不知道这是否重要。
使用实际列表(数组)而不是摆弄IFS:
#!/bin/bash
lines=( 'John Smith' 'James Johnson' )
for line in "${lines[@]}"; do
names=($line)
echo "$line"
read -p "Do you want to echo name? surname otherwise "
if [[ $REPLY == "y" ]]; then
echo "${names[0]}"
else
echo "${names[1]}"
fi
done
Run Code Online (Sandbox Code Playgroud)
当然,这假设您只有一个名字和一个姓氏,这对于真实的人来说是不正确的,但对于您的数据可能是正确的。无论如何,您的原始代码做出了相同的假设,所以我猜这对您来说不是问题。
您也可以通过在子shell中运行循环来按照您的想法进行操作,因此对 的任何更改IFS都只会影响子shell:
#!/bin/bash
lines='John Smith
James Johnson'
(
oIFS=$IFS
IFS=$'\n'
for line in $lines; do
echo "$line"
IFS=$oIFS
read name surname <<< "$line"
read -p "Do you want to echo name? surname otherwise "
if [[ $REPLY == "y" ]]; then
echo "$name"
else
echo "$surname"
fi
done
)
### The IFS hasn't been changed here outside the subshell.
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
300 次 |
| 最近记录: |