cmd2 `cmd1` 与 cmd1 | xargs cmd2

cmd2 `cmd1` 与 cmd1 | xargs cmd2

我正在尝试查找一个文件,find然后将找到的路径传递给sqlite3.sqlite>如果我的命令采用以下形式,我只会进入提示符:

sqlite3 `find . -type f -iname "*.db" | head -n1`

但这些形式不起作用:

find . -type f -iname "*.db" | head -n1 | xargs sqlite3
find . -type f -iname "*.db" | head -n1 | xargs -I% sh -c 'sqlite3 %;'

为什么后面的命令根本不执行任何操作?

答案1

在:

... | xargs cmd

根据实现,cmd的 stdin 是/dev/null或 那个管道。它不可能是外部标准输入,因为它会因管道而丢失。

$ echo /proc/self/fd/0 | gnu-xargs ls -ld
lr-x------ 1 me me 64 Dec 11 22:04 /proc/self/fd/0 -> /dev/null
$ echo /proc/self/fd/0 | busybox-or-solaris-...-xargs ls -ld
lr-x------    1 me me        64 Dec 11 22:04 /proc/self/fd/0 -> pipe:[99839]

无论哪种情况,sqlite3都无法读取您的任何输入。

这:

sqlite3 `find . -type f -iname "*.db" | head -n1`

命令获取由 返回的第一个文件路径的第一行find,根据 对其进行分割$IFS,对它们执行通配,并将结果单词作为不同的参数传递给 sqlite3。这没什么意义。

使用GNU find(可能是您正在使用的GNU -iname):

sqlite3 "$(find . -type f -iname "*.db" -print -quit)"

我们使用-exit告诉find在打印第一个找到的文件后退出。我们使用命令替换的现代形式$(...),并通过引用命令替换来跳过 split+glob 部分(这没有意义)。

您还可以使用(仍然是 GNU 特定的):

find . -type f -iname '*.db' \( -exec sqlite3 {} \; -o -true \) -quit

(尽管您会失去 的退出状态sqlite3)。

zsh

setopt extendedglob # best in ~/.zshrc
sqlite3 ./**/*.(#i)db(D.[1])

相关内容