題 xargs命令適用於ubuntu,但不適用於mac


我有以下代碼行,用於將我的項目中的個人日期變量更新為今天的當前日期。這條線在Ubuntu的終端上工作,但Mac終端似乎遠遠落後。不幸的是,我從某個網站複製了這個片段,所以我不確定它是如何工作的。建議?

grep -ilr --exclude=revar.sh --exclude=README.md "[DATE]" * |
    grep -v .git | xargs -i@ sed -i "s/\[DATE\]/${today}/g" @

4
2018-04-17 21:12


起源


@Migrators:這是一個編程問題,使用shell腳本作為語言(以及更新源代碼文件的目的)。它可能適合 都 SO和SU,但是因為它被問到了SO,為什麼要遷移呢?


答案:


它是如何工作的

  1. 生成文件名列表:

    grep -ilr --exclude=revar.sh --exclude=README.md "[DATE]" *
    

    以遞歸方式(-r)搜索文件,並列出(-l)文件內容不區分大小寫的那些名稱(-i)正則表達式'[DATE]'(這意味著該文件包含任何一個8個字符“AaDdEeTt”);排除名稱revar.sh和README.md,和

  2. 從列表中刪除包含字符後跟'git'的所有文件名(因此將刪除文件名'agitator'):

    grep -v .git
    
  3. 一次處理一個文件,將特定的“sed”腳本應用於該文件。在現代符號中(POSIX - 和MacOS X,以及Linux,AIX,HP-UX,Solaris等):

    xargs -I@ sed -i "s/\[DATE\]/${today}/g" @
    

    'sed'的'-i'選項意味著在處理後覆蓋輸入文件。這是在POSIX標準中未指定的'sed'的GNU和BSD擴展。

什麼是令人難以置信的

這個劇本可以在很多層面受到批評。

  • 第一個搜索字符串不正確;它應該在括號前有反斜杠;大多數文件至少包含一個字母'dateDATE'。
  • 第二個grep可能意味著刪除'.git'目錄下的任何內容並需要修復。
  • 與第一個'grep'不同,'sed'命令在查找'[DATE]'時不區分大小寫。

如何解決它

因此,兩種選擇中的一種是有道理的。

或者:

grep -ilr --exclude=revar.sh --exclude=README.md "\[DATE\]" * |
grep -v '\.git/' |
xargs sed -i "s/\[[Dd][Aa][Tt][Ee]\]/${today}/g"

要么:

grep -lr --exclude=revar.sh --exclude=README.md "\[DATE\]" * |
grep -v '\.git/' |
xargs sed -i "s/\[DATE\]/${today}/g"

正如Donal Fellows所指出的那樣,在這種情況下,沒有必要使用'-i'或'-I'選項來'xargs'。

即使修復它也有用嗎?

這讓我感到疑惑它是如何有用的。在第一天,所有出現的'[DATE]'都映射到'2010-04-17';第二天會發生什麼?如何在提交到git存儲庫之前取消映射日期?

不過,至少你現在知道它的作用以及它是如何做到的。


4
2018-04-17 22:15



我假設某種報導。有時探測太深也不值得......
就像@Donal說的那樣,你真的不想知道我為什麼需要這個。你的第二個例子實際上就是我想要的,感謝你的全面解釋。但好奇的是,它沒有將stdin傳遞給sed命令,它只是在sed命令中傳遞文件名。任何的想法? (我真的對Mac術語btw感到失望)。以下是參考錯誤:'sed:1:“changelog”:命令c期望\後跟文本' - Corey hart
@Corey:'$ {today}'有點像'17 / 04/2010'嗎?如果是這樣,您需要將's ///'符號更改為's %%%' - 使用%或其他任何模式中未出現的字符來分隔替換操作的各個部分。我不確定你怎麼會'認為'在混合中有一個改變命令。你是對的; xargs修復了一些事情,以便執行的命令為其輸入提供/ dev / null,並將文件名作為參數進行操作。通過從tcsh切換到理智的shell來解決Mac術語有什麼問題?你更喜歡哪種系統? - Jonathan Leffler


BSD xargs 不具有 -i,無論如何,該選項在GNU xargs中被棄用(本指南何時編寫?1995年?)。使用 -I 代替。


6
2018-04-17 21:15



謝謝,我只能在一天內學到很多,所以我非常依賴於我在互聯網上閱讀的東西。墮落是我猜的舊文章。 - Corey hart
是的,在mac應該使用 -I,例如 redis-cli keys 'foo*' | xargs -I@ echo @ - zhuguowei


-i 選項 xargs 當執行替換的地方在字符串的末尾時,永遠不需要;無論如何,這就是文件名的位置。和BSD xargs (這是OSX提供的)也不支持該選項。所以試試這個:

grep -ilr --exclude=revar.sh --exclude=README.md "[DATE]" * |
    grep -v .git | xargs sed -i "s/\[DATE\]/${today}/g"

3
2018-04-17 22:05





至於要在Mac OS X上進行sed的-i標誌以便就地編輯文件,你必須添加一個空字符串作為參數:

sed -i "" 's/regex/replace/g' file

sed -i "" 's/regex/'"${var}"'/g' file   # create sed expression using string concatenation

1
2018-04-18 07:22



或者用於創建備份文件名稱的擴展名。 sed -i ".BAK" 's/regex/replace/g' file 將創建一個名為“file.BAK”的備份文件。 - Dennis Williamson


使用Bash參數擴展您還可以幾乎自動避免sed格式問題:

# some basic Bash parameter expansion examples to play with
var='ddd/abc/ddd'
var="$(date)"
var=$'\\\n'

echo abc | sed 's/b/'"${var}"'/g'
echo abc | sed 's/b/'"${var//\//\\/}"'/g'

0
2018-04-18 07:50