題 Linux:對一批文件運行命令,並輸出匹配的輸出文件


一個簡單的任務:給定一個文件目錄和一個命令,它將一個文件作為輸入並生成一個文件作為輸出,我想一次處理目錄中的所有文件,並輸出相應的匹配名稱(帶有新的擴展名)。

所以如果命令通常是:

convert -input sourceFile.ext -output destFile.out

我想處理一個文件夾

file1.ext, file2.ext, etc.

並在相同的目錄中生成文件

file1.out, file2.out, etc.

有沒有辦法在終端中執行此操作而不編寫bash腳本?我對腳本編寫不是很熟悉,所以任何簡單的解決方案都會受到讚賞。


4
2017-10-15 23:22


起源




答案:


不使用 basename

for file in *.ext; do convert -input "$file" -output "${file/%ext/out}"; done

看到 http://www.gnu.org/software/bash/manual/bashref.html#Shell-Parameter-Expansion


10
2017-10-16 01:47



我必須執行以下操作才能獲得擴展名: ... -output "${file%.*}.wav"; rm "$file"; done。另外我做了一個'rm“$ file”,因為轉換後我不再需要輸入文件了 - Besi


看看 find 命令

務必 cd 到您的輸入目錄。

cd input_directory
find . -iname "*.ext" -exec convert -input {} -output {}.out \;

這導致了 .out 被附加到輸入文件的名稱。獲取您聲明的輸出文件我還沒想到。

嘗試什麼是明智的 find 在跑之前做的 -exec 改變了一切。

cd input_directory    
find  .  -iname "*.ext"  -type f  -exec ls -l {} \;

會做一種“幹運行”。

  • -exec 什麼命令運行
  • {} 找到了什麼文件;一次一個
  • \;  需要用這個來結束 -exec

我的有限實驗表明你不需要引用{}

$ find . -type f -exec ls -bl {} \;  
-rw-r--r--. 1 me me 0 Oct 20 19:03 ./a\ b\ c.txt  
-rw-r--r--. 1 me me 0 Oct 20 19:03 ./abc.txt  

$ ls -bl
total 0
-rw-r--r--. 1 me 0 Oct 20 19:03 a\ b\ c.txt
-rw-r--r--. 1 me 0 Oct 20 19:03 abc.txt
me ~/a $`

我有一個文本文件help.txt,其中包含我難以記住的bash命令的提示。我把它綁在一個簡單的腳本上打印出文件..,h

這是我的find命令列表:

# searches for all files on the system for the string you fill in between the ""
sudo find  /  -type f -exec grep -il "" {} \;
# search for all files starting with python.
find / -iname 'python*'
# search for the file type .jpeg and sort the list by date
find  ~  -iname "*.jpeg" -type f  -exec ls -l  {} \; 2>/dev/null | sort -r -k 8,8 -k 6,7M
# so I can remember the or syntax. 
find  ~  \( -iname "*.jpeg" -o -iname "*.png"  \) -type f  -exec ls -l  {} \;

5
2017-10-15 23:41



nispio:你做“{}”擔心空白嗎?也許你需要一個/之前$(basname ...?我太新了,不能在你的帖子中添加評論:( - historystamp
是。報價主要是為了避免空格問題。 - nispio
如果命令(在這種情況下轉換)支持使用路徑,那麼您甚至可能不需要cd到目標目錄。只是用 find /path/to/folder  而不是 find .。 - Hennes


試試這個(這一切都是一行):

find /path/to/folder -maxdepth 1 -iname \*.ext -exec sh -c 'convert -input "{}" -output "/path/to/folder/$(basename "{}" .ext).out"' \;

這是細分:

find /path/to/folder -maxdepth 1 -iname \*.ext

搜索所有以。結尾的文件 .ext 在 /path/to/folder 但不在子文件夾中。該 -exec 部分告訴find命令如何處理它找到的每個文件。每次出現 {} 然後用文件替換。模式是

find /path/to/folder -iname \*.ext -exec echo "found this file: {}" \;

正如我所說, {} 擴展為找到的文件的名稱。該 \; 標誌著結束了 -exec 參數。該 sh -c 在這種情況下使用,因為否則命令 $(basename {} .ext) 過早地會被shell擴展。因此,我們將其括在單引號中以防止擴展並將其傳遞給shell的另一個實例。該 {} 將擴大 find,其餘的命令將逐字傳遞給 sh。命令

$(basename "filename.ext" .ext).out

將剝離擴展名 "filename.ext" 並追加 .out 延期。

編輯

我剛剛意識到該命令必須看起來是多麼無法接近。這是它最簡單的版本。

find . -name \*.ext -exec sh -c 'convert -input {} -output $(basename {} .ext).out' \;

幾乎 適合這次不滾動。 :)


4
2017-10-15 23:33





這取決於你“寫一個bash腳本”的含義。 以下是bash腳本,但如果需要,您只需將其輸入終端即可; 你不必把它放到一個文件中:

cddirectory_where_the files_are
for x in *.ext
do
        convert -input "$x" -output $(basename "$x" .ext).out
done

這只會在 *.ext 您目錄中的文件 cd 至。 如果你想搜索子目錄, find 是最好的解決方案;例如。, 使用 nispio的回答但遺漏了 -maxdepth 1


編輯:Hennes對nispio的回答的評論也適用於此;你可以說

for x in /path/to/folder/*.ext
do
        convert -input "$x" -output $(basename "$x" .ext).out
done


2
2017-10-16 00:04



這比嘗試記住我的答案所帶來的所有語法更容易。您甚至可以通過添加一些分號將其變成“單線”: for x in *.ext; do convert -input "$x" -output $(basename "$x" .ext).out; done - nispio
如果您經常需要這樣做,不希望每次都輸入命令,然後將其保存到文件中。加 #!/usr/bin/env bash 作為 第一行 並將腳本設置為可執行文件 chmod +x scriptname。 - Hennes
@Hennes:問題是,“有沒有辦法做到這一點......沒有寫一個bash腳本?” - Scott
真正。但即使是單行也似乎要長期或者復雜地定期輸入。因此,您可以將命令保存在文件中以進行複制和粘貼。如果你這樣做,那麼為什麼不讓那個文件可執行。除此之外,OP並沒有特別提到他不是在尋找bash腳本,而是他對腳本編寫並不十分熟悉。在我看來,這與一個非常簡單,解釋良好的劇本並不衝突。 - Hennes
那很奇怪; “如果沒有編寫bash腳本,有沒有辦法在終端中執行此操作?” 對我來說似乎相當具體。 - Scott