
我想刪除具有size = 0
.所以我嘗試:
find ./ -size 0 | xargs rm
但是,它對於名稱以空格開頭的檔案有問題。
在網路上搜尋我發現了這個:
find ./ -size 0 -exec rm -i {} \;
有用。但是,我認為我的使用方式xargs
對此來說過於複雜。
這是什麼{} \;
意思?
有人可以幫我解釋一下嗎?
我的英文不是很好,所以請使用簡單的寫作。
答案1
{}
絕對沒有任何意義bash
,因此在此處未經修改地作為參數傳遞給所執行的命令find
。
另一方面,;
具有特定的含義bash
。當順序命令位於同一命令行時,它通常用於分隔它們。這裡的反斜線 in\;
精確地用於防止分號被解釋為命令分隔符,bash
然後允許它作為參數傳遞給底層命令find
。引用分號,即";"
或';'
,可能是使其不被處理的另一種方法。
命令:
find ./ -size 0 -exec rm -i {} \;
意思是:在當前目錄中查找(注意,/
這裡沒有用,.
無論如何都只能是一個目錄)任何大小為 0 的對象,對於找到的每個對象,運行命令rm -i name
,即如果要刪除,則交互式提示每個文件它。{}
被執行命令中找到的每個檔案名稱取代。一個很好的功能是,該檔案名稱嚴格來說是一個參數,無論檔案名稱是什麼(甚至包含嵌入的空格、製表符、換行符和任何字元)。xargs
除非使用不可移植的 hack,否則情況不會如此。決賽;
是為了結束該-exec
條款。之所以需要對其終點進行界定,是因為其他find
選項可能會跟隨該-exec
選項,儘管這種情況很少這樣做。例如:
find . -name "*.js" -exec ls -l {} \; -name "special*" -exec wc -l {} \;
此命令的一個問題是它不會忽略非普通文件,因此可能會提示使用者刪除套接字、區塊和字元設備、管道和目錄。即使你回答“是”,後者總是會失敗。
另一個問題(雖然在這裡並不重要)是rm
每個大小為零的檔案都會呼叫它。如果您替換-exec
結尾 from/;
到+
,將透過僅呼叫盡可能少的次數(通常只呼叫一次)來find
優化子流程建立。rm
以下是我修改此命令的方法:
find . -type f -size 0 -exec rm -i {} +
答案2
使用 時find -exec
,{}
會擴展到找到的每個結果。
例如,如果您有一個example
包含 3 個檔案的目錄a.txt
,b.txt
並且c.txt
,find example/ -exec rm -i {} \;
將擴展為:
find example/ -exec rm -i example/a.txt \;
find example/ -exec rm -i example/b.txt \;
find example/ -exec rm -i example/c.txt \;
\;
末尾的 是簡單的轉義符,用於;
指示 exec 模式的結束。否則,它會被 shell 本身解釋。
答案3
與find
命令的exec
選項結合使用,該{}
部分將替換為執行命令時找到的檔案的名稱。也很\;
重要,因為它定義了正在執行的命令的結束
例如
find ~ -name \*.bak -exec -rm -f {} \;
將刪除.bak
以使用者主目錄或其中包含的資料夾中任意位置結尾的所有檔案。透過執行rm -f
找到的每個檔案。
xargs
取得標準輸入行(通常來自管道),並在執行您給它的命令時從中形成參數的尾部部分
答案4
這是一個老問題,但我想添加更多資訊:
find ./ -size 0 -exec rm -i {} \;
在上一個指令中,\;
是轉義分號。這會阻止 shell 處理該命令(即通常;
會分隔命令)。
此-exec
參數將所有內容解釋為轉義分號之前的命令\;
(即,rm -i {}
它將是由 執行的內部命令find
)。在內部命令中,{}
代表參數擴展。在痛苦英語中,它的意思是「插入在這裡找到的檔案名稱」。
因此,如果找到的檔案是“file-a.txt”和“file-b.txt”,find
則會執行rm -i file-a.txt
then rm -i file-b.txt
。
此命令的一個問題是它不會忽略非普通文件,因此可能會提示使用者刪除套接字、區塊和字元設備、管道和目錄。即使您回答“是”,後者也總是會失敗(即需要遞歸刪除目錄)
另一個問題(雖然在這裡並不重要)是rm
每個大小為零的檔案都會呼叫它。如果您將-exec
結尾替換為/;
to , find 將透過僅呼叫盡可能少的次數(通常只呼叫一次)來+
優化子流程建立。rm
以下是我修改此命令的方法:
find ./ -type f -size 0 -exec rm -i {} +
curly brackets
或braces
:{}
可以以不同的方式使用
支撐擴張
大括號可用於建構序列:
### prints out the numbers from 0 to 10
echo {0..10}
## prints out the same numbers, but in reverse order
echo {10..0}
## prints every second number, from 10 to 0
echo {10..0..2}
## prints every second letter, from z and working its way backwards to a.
echo {z..a..2}
我們也可以組合兩個或多個序列:
## prints out a pair of letters, from aa to zz.
echo {a..z}{a..z}
添加前綴和後綴:
### adds '"' as prefix and suffix
echo \"{These,words,are,quoted}\"
# output: "These" "words" "are" "quoted"
# concatenates the files file1, file2, and file3 into combined_file.
cat {file1,file2,file3} > combined_file
# copies "file22.txt" to "file22.backup"
cp file22.{txt,backup}
筆記:
大括號內不允許有空格,{...}
除非空格是引或者逃脫了。
echo {file1,file2}\ :{\ A," B",' C'}
# output: file1 : A file1 : B file1 : C file2 : A file2 : B file2 : C
擴展支撐擴展。
大括號可用於建立數組。 Bash 中的陣列是透過將元素放在括號之間()
並使用空格分隔每個元素來定義的,如下所示:
month=("Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec")
要存取數組中的元素,可以使用括號內的索引[]
:
# Array indexes start at [0], so [3] points to the fourth item
$ echo ${month[3]}
## output: Apr
因此,我們可以建立一個類似這樣的陣列:
## builds an array that contains all the 2-letter combinations of the entire alphabet.
letter_combos=({a..z}{a..z})
## contains all the binary numbers for an 8-bit register, in ascending order,
## from 00000000, 00000001, 00000010, etc., to 11111111.
dec2bin=({0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1}{0..1})
最後一個特別有趣,因為 dec2bin 現在我們可以使用它來建立一個 8 位元十進位到二進位轉換器。假設您想知道 25 的二進制數是多少。你可以這樣做:
$ echo ${dec2bin[25]}
## output: 00011001
但是Teo有沒有更好的方法將十進制轉換為二進制?
- 是的,有,但仍然很有趣,對吧?
分組命令
{ ... }
可用於放置要在目前 shell 上下文中執行的命令清單。不子殼被建造。列表後面的分號;
(或換行符號)是必需的。
括號()
用於在 a 中運行命令子殼:
menu_type=bar
echo $menu_type
## output: bar
## new lets called in a sub-shell
(menu_type=superbar; echo $menu_type)
## output: superbar
## back to the context
echo $menu_type
## output: bar
我們無法取得superbar
的新值menu_type
。
但是,如果我們運行這樣的程式碼:
{ menu_type=superbar; echo $menu_type; }
## output: superbar
echo $menu_type
## output: superbar
{ ... }
不會建立子 shell,這就是我們可以存取該menu_type
值的原因。
{ ... }
也稱為 an inline group
,實際上,它創建了一個匿名函數(即沒有名稱的函數)。用簡單的英語來說,與「標準」函數不同,a 中的變數{ ... }
對腳本的其餘部分仍然可見。
此外,{ ... }
還可用於stdout
將多個命令的輸出分組到其stdin
.讓我們來看一個例子:
#!/bin/bash
# rpm-check.sh
# Queries an rpm file for description, listing, and whether it can be installed.
# Saves output to a file.
SUCCESS=0
E_NOARGS=65
if [ -z "$1" ]; then
echo "Usage: `basename $0` rpm-file"
exit $E_NOARGS
fi
{ # Begin command group.
echo
echo "Archive Description:"
rpm -qpi $1 # Query description.
echo
echo "Archive Listing:"
rpm -qpl $1 # Query listing.
echo
rpm -i --test $1 # Query whether rpm file can be installed.
if [ "$?" -eq $SUCCESS ]
then
echo "$1 can be installed."
else
echo "$1 cannot be installed."
fi
echo # End command group.
} > "$1.test" # Redirects output of everything in block to file.
echo "Results of rpm test in file $1.test"
exit 0
現在,看看如何在群組中進行 I/O 重定向stdin
:
#!/bin/bash
File=/etc/fstab
## reads the first two lines of the file
{
read line1
read line2
} < $File
echo "First line in $File is:"
echo "$line1"
echo
echo "Second line in $File is:"
echo "$line2"
exit 0
將命令組的輸出儲存到檔案中的另一個範例
## exec commands sequentially and redirects the output of the ls command into the png-list.txt file
echo "I found all these png files:"; find . -iname "*.png"; echo "Within this bunch of files:"; ls > png-list.txt
## exec commands sequentially and redirects the output of the group into the png-list.txt file
{ echo "I found all these png files:"; find . -iname "*.png"; echo "Within this bunch of files:"; ls; } > png-list.txt
有什麼區別,特奧?
好吧,年輕學徒。第二個建立包含所有輸出的文件png-list.txt
,從行 開始“I found all these png files:“
,以命令輸出結束ls
。
子殼駭客
{ ... }
Bash 為大括號組指令建立一個子 shell當且僅當它是管道的一部分,例如:
$ { A=1; { A=2; sleep 2; } ; echo $A; }
## output: 2
$ { A=1; { A=2; sleep 2; } | sleep 1; echo $A; }
## output: 1
筆記:
大括號和大括號內的指令清單之間有空格。這是因為{
和}
是保留字(即內建在 shell 中的指令)。此外,命令清單必須以分號結尾;
或使用換行符號分隔命令。
參數擴充
好吧,回到
month=("Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec")
echo ${month[3]}
## output: Apr
這裡的大括號{}
不被用作序列建構器的一部分,而是作為產生參數擴展的一種方式。參數擴展涉及到盒子上的說明:
它採用大括號內的變數或表達式並將其擴展為它所代表的任何內容。
特奧這意味著什麼?
嗯,這意味著${...}
告訴 shell 擴展其內部的所有內容。本例中,month
就是我們先前定義的數組,即:
month=("Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec")
並且,3
數組中的 item 指向"Apr"
(即 Bash 中數組中的第一個索引是[0]
)。這意味著echo ${month[3]}
擴展後會轉換為 echo "Apr"
。
將變數解釋為其值是擴展變數的一種方法,但我們也可以利用更多方法。我們可以使用參數擴展來操縱從變數中讀取的內容(即透過從末尾切掉一塊)。
假設你有一個像這樣的變數:
a="This sentence is too longgg"
## chops off the last two gs
echo ${a%gg}
## output: This sentence is too long
這對於將文件從一種格式轉換為另一種格式非常有用。例如,如果我們有一個命令,將名為 的 JPEG 影像image.jpg
轉換為名為 的 PNG 映像image.png
:
convert image.jpg image.png
我們可以這樣重寫:
i='image.jpg'
## chops off the extension 'jpg' and adds 'png'
convert $i "${i%jpg}png"
## output: convert image.jpg image.png
但是 teo 這怎麼能比僅僅寫在檔案名稱中更有用呢?
好吧,當我們有一個包含數百張 JPEG 映像的目錄時,您需要轉換為 PNG,只需在其中執行以下命令:
for i in *.jpg; do convert $i ${i%jpg}png; done
....所有圖片都會自動轉換。歡迎您的年輕學徒。
如果您需要從變數的開頭截掉一個區塊,%
請使用#
:
$ a="Hello World!"
## chops off the word 'Hello' and adds 'Goodbye'
$ echo Goodbye${a#Hello}
## output: Goodbye World!
文字佔位符
之後使用xargs -i
(即替換字串選項)。雙{}
大括號是輸出文字的佔位符。
## Execute 'echo ./<file>' for each file in the directory
ls . | xargs -i -t echo ./{} $1
# ^^ ^^
路徑名
路徑名是包含完整路徑的檔案名稱。舉個例子,/home/<user>/Notes/todo.txt
。這有時稱為絕對路徑。我們將在包含 的構造{}
中遇到大部分情況。然而,這不是 shell 內建的。如果包含,則 find 會取代所選檔案的完整路徑名。find
-exec <command> \;
<command>
{}
"{}"
# Removes all core dump files from user's home directory.
find ~/ -name 'core*' -exec rm {} \;