Bash find 或 xargs 只对变量和子 shell 求值一次
Bash find or xargs evaluates variables and subshells only once
我注意到 find ... -exec ... {} \;
或 xargs -i ... {}
似乎只评估变量或子 shell(如 $RANDOM
或 $(uuidgen)
)一次,即使命令被执行多次。
例如:
$ find . -type f -name \*.txt -exec echo "$RANDOM {}" \;
28855 ./foo/bar.txt
28855 ./foo/bar1.txt
28855 ./foo/bar2.txt
28855 ./foo/bar3.txt
28855 ./foo/bar4.txt
$ grep -lr SOME_TEXT --include=\*.txt | xargs -i echo "$RANDOM {}"
6153 ./foo/bar.txt
6153 ./foo/bar1.txt
6153 ./foo/bar2.txt
6153 ./foo/bar3.txt
6153 ./foo/bar4.txt
有没有办法得到如下结果?
1543 ./foo/bar.txt
543 ./foo/bar1.txt
57224 ./foo/bar2.txt
3525 ./foo/bar3.txt
18952 ./foo/bar4.txt
是的。变量扩展在行被接受之后执行,但在执行之前执行。这意味着最终被执行的命令是
'/usr/bin/find' '.' '-type' 'f' '-name' '*.txt' '-exec' 'echo' '28855 {}' ';'
解决这个问题的两种基本方法:
使用另一个会延迟执行的bash
:
find . -type f -name \*.txt -exec bash -c 'echo "$RANDOM {}"' \;
使用循环:
for file in $(find . -type f -name \*.txt -print)
do
echo "$RANDOM $file"
done
如果你的文件有空格,你必须做一些不同的事情来保留它们:
mapfile -d '' files < <(find . -type f -name \*.txt -print0)
for file in "${files[@]}"
do
echo "$RANDOM $file"
done
我注意到 find ... -exec ... {} \;
或 xargs -i ... {}
似乎只评估变量或子 shell(如 $RANDOM
或 $(uuidgen)
)一次,即使命令被执行多次。
例如:
$ find . -type f -name \*.txt -exec echo "$RANDOM {}" \;
28855 ./foo/bar.txt
28855 ./foo/bar1.txt
28855 ./foo/bar2.txt
28855 ./foo/bar3.txt
28855 ./foo/bar4.txt
$ grep -lr SOME_TEXT --include=\*.txt | xargs -i echo "$RANDOM {}"
6153 ./foo/bar.txt
6153 ./foo/bar1.txt
6153 ./foo/bar2.txt
6153 ./foo/bar3.txt
6153 ./foo/bar4.txt
有没有办法得到如下结果?
1543 ./foo/bar.txt
543 ./foo/bar1.txt
57224 ./foo/bar2.txt
3525 ./foo/bar3.txt
18952 ./foo/bar4.txt
是的。变量扩展在行被接受之后执行,但在执行之前执行。这意味着最终被执行的命令是
'/usr/bin/find' '.' '-type' 'f' '-name' '*.txt' '-exec' 'echo' '28855 {}' ';'
解决这个问题的两种基本方法:
使用另一个会延迟执行的
bash
:find . -type f -name \*.txt -exec bash -c 'echo "$RANDOM {}"' \;
使用循环:
for file in $(find . -type f -name \*.txt -print) do echo "$RANDOM $file" done
如果你的文件有空格,你必须做一些不同的事情来保留它们:
mapfile -d '' files < <(find . -type f -name \*.txt -print0) for file in "${files[@]}" do echo "$RANDOM $file" done