Shell-Script

cmd2 cmd1 與 cmd1 |xargs cmd2

  • December 11, 2014

我試圖找到一個文件,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 %;'

為什麼後面的命令什麼都不做?

在:

... | xargs cmd

根據實現,cmd的標準輸入是/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(可能是您使用以來所使用的-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])

引用自:https://unix.stackexchange.com/questions/173833