在“查找”命令上下文中,“{} \;”是什么意思?

在“查找”命令上下文中,“{} \;”是什么意思?

我想删除包含的文件size = 0。因此我尝试:

find ./ -size 0 | xargs rm

但是,对于名称以空格开头的文件,它存在问题。

在互联网上搜索我发现了这个:

find ./ -size 0 -exec rm -i {} \;

可以。但是,我认为我的方法xargs太复杂了。

这是什么{} \;意思?

有人可以解释一下吗?

我的英语不是很好,所以请使用简单的书写。

答案1

{}对 来说完全没有任何意义bash,因此不加修改地作为参数传递给这里执行的命令find

另一方面,;对 有特定含义bash。它通常用于分隔同一命令行上的连续命令。此处的反斜杠\;恰好用于防止分号被 解释为命令分隔符,bash然后允许它作为参数传递给底层命令find。引用分号,即";"';',可能是使其保持未处理的另一种方法。

命令:

find ./ -size 0 -exec rm -i {} \;

意思是:在当前目录中查找(请注意,/这里的 是无用的,因为.它无论如何只能是一个目录)任何大小为 0 的对象,对于找到的每个对象,运行命令rm -i name,即以交互方式提示每个文件是否要删除它。{}替换为执行命令中找到的每个文件名。 一个很好的特性是,无论文件名是什么(即使包含嵌入的空格、制表符、换行符和任何字符),这个文件名都严格是一个参数。xargs除非使用不可移植的黑客, 情况并非如此。 最后;是结束该-exec子句。 它的结尾需要定界的原因是其他find选项可能跟在它-exec后面,尽管很少这样做。 例如:

find . -name "*.js" -exec ls -l {} \; -name "special*" -exec wc -l {} \;

此命令的一个问题是它不会忽略非纯文本文件,因此可能会提示用户删除套接字、块和字符设备、管道和目录。即使您回答是,它也会因后者而失败。

另一个问题(虽然在这里并不是很关键)是,rm对于每个大小为零的文件,都会调用 。如果将-exec结尾从替换/;+,将通过仅调用尽可能少的次数(通常仅调用一次)来find优化子进程的创建。rm

以下是我修改此命令的方法:

find . -type f -size 0 -exec rm -i {} +

答案2

当使用时find -exec{}会扩展到找到的每个结果。

例如,如果你有一个example包含 3 个文件的目录a.txtb.txtc.txtfind 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.txtrm -i file-b.txt

此命令的一个问题是它不会忽略非纯文本文件,因此可能会提示用户删除套接字、块和字符设备、管道和目录。即使您回答是,它也会始终失败(即需要递归删除目录)

另一个问题(虽然在这里并不是很关键)是,rm对于每个大小为零的文件,都会调用 。如果将-exec结尾从替换/;为, find 将通过仅调用尽可能少的次数(通常仅调用一次)来+优化子进程的创建。rm

以下是我修改此命令的方法:

find ./ -type f -size 0 -exec rm -i {} +

curly bracketsbraces{}可以以不同的方式使用

括号扩展

大括号可用于构建序列:

### 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 上下文中执行的命令列表。否子壳已创建。列表后面的分号;(或换行符)是必需的

括号()用于在子壳

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值的原因。

{ ... }也称为inline group,实际上,它创建了一个匿名函数(即没有名称的函数)。简单地说,与“标准”函数不同, 中的变量{ ... }对脚本的其余部分仍然可见。

此外,{ ... }还可用于将多个命令的输出分组到其中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

有什么区别,Teo?

好吧,年轻的徒弟。第二个创建了包含所有输出的文件png-list.txt,从行开始“I found all these png files:“,到命令输出结束ls

子 shell 攻击

{ ... }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

此处括号{}并非作为序列生成器的一部分使用,而是作为生成参数扩展的一种方式。参数扩展涉及框上的内容:

它采用括号内的变量或表达式并将其扩展为其所代表的内容。

Teo,这是什么意思?

嗯,它的意思是${...}告诉 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

但是,这怎么会比仅仅写入文件名称更有用呢?

好吧,当我们有一个包含数百张 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。这有时被称为绝对路径。我们{}主要会在find包含的构造中遇到-exec <command> \;。但是,这不是 shell 内置命令。如果<command>包含{},则 find 会用所选文件的完整路径名替换"{}"

# Removes all core dump files from user's home directory.
find ~/ -name 'core*' -exec rm {} \;

相关内容