如何以优雅的方式对子文件夹中具有特定扩展名的所有文件执行操作?


18

我目前最好的选择是:

for i in $(find . -name *.jpg); do echo $i; done

问题:不处理文件名中的空格。

注意:我也希望采用图形方式来执行此操作,例如“ tree”命令。


您不能简单地加上引号$i吗?我做到了,效果很好。这种方法有什么问题吗?
Umar Farooq Khawaja'3

Answers:


26

规范的做法是

find . -name '*.jpg' -exec echo {} \;

(替换\;+一个以上的文件传递给echo在时间)

或(特定于GNU,尽管某些BSD现在也有它):

find . -name '*.jpg' -print0 | xargs -r0 echo

zsh:

for i (**/*.jpg(D)) echo $i

2
如果您正在使用xargs的-0,你应该匹配它发现-0
itsbruce

1
@MichaelKjörling,不使用引号{}没有区别。{}由find而不是shell扩展。不会使用一种改进来echo扩展转义序列,例如\b(至少是Unix兼容echo的)。
斯特凡Chazelas

1
@sch确定吗?该find手册页显示find . -type f -exec file '{}' \;EXAMPLES部分。也许有些贝壳会专门处理牙套。
QuasarDonkey,2012年

1
引号不会造成伤害,但没什么区别。所有的'{}'\{\}{}"{}"'{'}由外壳(任何类似Bourne外壳)扩展到一个参数,发现是两个字符“{”和“}”。将“查找”替换为“回声查找”,或者printf '<%s>\n' find如果您要仔细检查,则将其替换。
斯特凡Chazelas


2

已经给出了更好的答案。

但是请注意,空格并不是您提供的代码中的唯一问题。标签,换行符和通配符也是一个问题。

IFS='
'
set -f
for i in $(find . -name '*.jpg'); do echo "$i"; done

那么只有换行符是一个问题。


1

您所提到的是人们尝试读取文件名时面临的基本问题之一。有时,知识有限且对文件和文件夹结构有误解的人往往会忘记“ 在UNIX中,一切都是文件 ”。因此,他们不知道他们也需要处理空格,因为文件名可以包含2个或更多带空格的单词。

解决方案:因此,执行此操作的最知名方法之一是进行完整读取

我们将在这里读取存在的所有文件并将它们保存在变量中,下一次在进行所需的处理时,我们只需要将该变量保留在引号内即可将文件名保留空格。这是执行此操作的基本方法之一,但是其他人在此处提供的其他答案也同样有效。

脚本:

 find /path/to/files/ -iname "*jpg" | \
  while read I; do
   cp -v --parent "$I" /backup/dir/
  done

在这里,我通过给它们提供路径来读取文件,无论读取什么,我都将它们保存在变量I中,稍后我将在处理该文件时引用该变量以保留空间以便正确处理它。

希望这对您有所帮助。


1
“一切都是文件”指的是其他东西。您的解决方案是针对GUN的,并且不能处理文件名中的反斜杠或换行符。Shell中的“ while read”循环(IMO)通常表示不良的Shell脚本实践。
斯特凡Chazelas

@sch:呵呵,我以前认为,没关系。感谢您指出这一点。我可能需要更多地研究它。
黑暗骑士

对不起,我的意思是“GNU”,而不是“枪”以上(这是我第一次意识到这些都是字谜BTW ...)
斯特凡Chazelas

1

只需使用findbash

find . -name '*.jpg' -exec bash -c '
    echo "treating file $1 in bash, from path : ${1%/*}" 
' -- {} \;

这样,我们$1在bash中使用,就像在基本脚本中一样,使用bash打开漂亮的视角来执行任何高级(或不执行)任务。

一种更有效的方法(避免必须为每个文件启动新的bash):

find . -name '*.jpg' -exec bash -c 'for i do
    echo "treating file $i in bash, from path : ${i%/*}" 
  done' -- {} +

0

在最新版本的bash中,可以使用以下globstar选项:

shopt -s globstar
for file in **/*.jpg ; do
    echo "$file"
done

对于简单的操作,您甚至可以完全跳过循环:

echo **/*.jpg

尽管该功能在zsh(功能的起源地)和ksh93(具有set -G)中有效,但不应将其用于bash中,因为bash版本从根本上被破坏(就像GNU一样grep -r),因为它会下降到目录的符号链接中(等效于find -Lzsh或***/*.jpg)。另请注意,与find相反,它将忽略点文件,而不会下降到dotdirs(默认情况下)。
斯特凡Chazelas
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.