Bash 个子描述符 shell
Bash descriptors in sub shell
下面的代码片段旨在收听和 select 目录中的几首歌曲:
exec 3<&1
find /some/directory -name '*.mp3' -print0 | xargs -0 bash -c '
for i; do
mplayer -ss 10 "$i" 1<&3
read -p "Select? (y/n)" -n 1 choice 1<&3
if [ "$choice" = "y" -o "$choice" = "Y" ]; then
echo "$i" > /tmp/selected_songs.txt
fi
done
'
exec 3<&-
本意是让 mplayer
和 shell read
接受键盘输入,但没有成功!为此,我认为 FD 3 将指向 find
和 xargs
进程的键盘输入。这再次传递给 xargs
执行的 shell,其中执行了 mplayer
和 shell read
;但它没有!
这里出了什么问题?
首先,我认为你让这件事变得比它必须的更难了。如果你有 bash 4,请使用 globstar。
shopt -s globstar
for i in /some/directory/**/*.mp3; do
mplayer -ss 10 "$i"
read -p "Select? (y/n)" -n 1 choice
case "$choice" in
[yY]) echo "$i" >> /tmp/selected_songs.txt;;
esac
done
即使您不这样做,也可以使用 find … -exec bash -c 'yourscript' _ {} +
而不是 xargs
。
(我还将您的 >
更改为 >>
因为我假设您不想在每次通过时截断文件。)
至于理解问题,这里有各种复杂的问题,但我会指出一些重要的事情:
- 标准输入为 FD 0,但
exec 3<&1
将 1 复制为 3 并打开它以供 阅读。
- 您似乎在尝试更改键盘输入进行的位置。这很棘手,因为这样做类似于将 EOF 发送到交互式 shell。大多数 shell 遇到这种情况都会关闭。相反,请考虑更改 xargs 获取输入的位置,而不要管键盘。 (BSD
xargs
具有相关的 -o
选项。请查看您的联机帮助页。)
- 您正在对 mplayer 和无超时读取进行相同的重定向。如果你正在循环阅读,当你提供输入时,你如何知道你在循环中的什么位置?
傻我!应该重定向的是 FD 0——而不是 1。按以下预期工作的版本:
exec 3<&0
find /media/jeenu/USB/ -type f -print0 | xargs -0 bash -c '
for i; do
mplayer -ss 10 "$i"
read -p "Select? (y/n/q)" -n 1 choice
case "$choice" in
[yY]) echo "$i" >> /tmp/selected_songs.txt;;
[qQ]) break;;
esac
done 0<&3
'
exec 3<&-
如果你想要一个带有 bash 的子 shell,那么你可以这样做:
find /media/jeenu/USB/ -type f -print0 | xargs -0 bash <<EOF
#This is a bash subshell
#put your code here
EOF
下面的代码片段旨在收听和 select 目录中的几首歌曲:
exec 3<&1
find /some/directory -name '*.mp3' -print0 | xargs -0 bash -c '
for i; do
mplayer -ss 10 "$i" 1<&3
read -p "Select? (y/n)" -n 1 choice 1<&3
if [ "$choice" = "y" -o "$choice" = "Y" ]; then
echo "$i" > /tmp/selected_songs.txt
fi
done
'
exec 3<&-
本意是让 mplayer
和 shell read
接受键盘输入,但没有成功!为此,我认为 FD 3 将指向 find
和 xargs
进程的键盘输入。这再次传递给 xargs
执行的 shell,其中执行了 mplayer
和 shell read
;但它没有!
这里出了什么问题?
首先,我认为你让这件事变得比它必须的更难了。如果你有 bash 4,请使用 globstar。
shopt -s globstar
for i in /some/directory/**/*.mp3; do
mplayer -ss 10 "$i"
read -p "Select? (y/n)" -n 1 choice
case "$choice" in
[yY]) echo "$i" >> /tmp/selected_songs.txt;;
esac
done
即使您不这样做,也可以使用 find … -exec bash -c 'yourscript' _ {} +
而不是 xargs
。
(我还将您的 >
更改为 >>
因为我假设您不想在每次通过时截断文件。)
至于理解问题,这里有各种复杂的问题,但我会指出一些重要的事情:
- 标准输入为 FD 0,但
exec 3<&1
将 1 复制为 3 并打开它以供 阅读。 - 您似乎在尝试更改键盘输入进行的位置。这很棘手,因为这样做类似于将 EOF 发送到交互式 shell。大多数 shell 遇到这种情况都会关闭。相反,请考虑更改 xargs 获取输入的位置,而不要管键盘。 (BSD
xargs
具有相关的-o
选项。请查看您的联机帮助页。) - 您正在对 mplayer 和无超时读取进行相同的重定向。如果你正在循环阅读,当你提供输入时,你如何知道你在循环中的什么位置?
傻我!应该重定向的是 FD 0——而不是 1。按以下预期工作的版本:
exec 3<&0
find /media/jeenu/USB/ -type f -print0 | xargs -0 bash -c '
for i; do
mplayer -ss 10 "$i"
read -p "Select? (y/n/q)" -n 1 choice
case "$choice" in
[yY]) echo "$i" >> /tmp/selected_songs.txt;;
[qQ]) break;;
esac
done 0<&3
'
exec 3<&-
如果你想要一个带有 bash 的子 shell,那么你可以这样做:
find /media/jeenu/USB/ -type f -print0 | xargs -0 bash <<EOF
#This is a bash subshell
#put your code here
EOF