Sam*_*hke 12 bash find filenames
虽然我已经使用 BASH 好几年了,但我在 BASH 脚本方面的经验相对有限。
我的代码如下。它应该从当前目录中获取整个目录结构并将其复制到$OUTDIR
.
for DIR in `find . -type d -printf "\"%P\"\040"`
do
echo mkdir -p \"${OUTPATH}${DIR}\" # Using echo for debug; working script will simply execute mkdir
echo Created $DIR
done
Run Code Online (Sandbox Code Playgroud)
问题是,这是我的文件结构示例:
$ ls
Expect The Impossible-Stellar Kart
Five Iron Frenzy - Cheeses...
Five Score and Seven Years Ago-Relient K
Hello-After Edmund
I Will Go-Starfield
Learning to Breathe-Switchfoot
MMHMM-Relient K
Run Code Online (Sandbox Code Playgroud)
请注意空格 :-S 并for
逐字接受参数,因此我的脚本输出如下所示:
Creating directory structure...
mkdir -p "/myfiles/multimedia/samjmusicmp3test/Learning"
Created Learning
mkdir -p "/myfiles/multimedia/samjmusicmp3test/to"
Created to
mkdir -p "/myfiles/multimedia/samjmusicmp3test/Breathe-Switchfoot"
Created Breathe-Switchfoot
Run Code Online (Sandbox Code Playgroud)
但我需要它从find
. 我也试过find
在每个文件名周围加上双引号。但这没有帮助。
for DIR in `find . -type d -printf "\"%P\"\040"`
Run Code Online (Sandbox Code Playgroud)
并使用更改后的行输出:
Creating directory structure...
mkdir -p "/myfiles/multimedia/samjmusicmp3test/"""
Created ""
mkdir -p "/myfiles/multimedia/samjmusicmp3test/"Learning"
Created "Learning
mkdir -p "/myfiles/multimedia/samjmusicmp3test/to"
Created to
mkdir -p "/myfiles/multimedia/samjmusicmp3test/Breathe-Switchfoot""
Created Breathe-Switchfoot"
Run Code Online (Sandbox Code Playgroud)
现在,我需要一些可以像这样迭代的方法,因为我还希望运行一个更复杂的命令,该命令涉及gstreamer
以下类似结构中的每个文件。我该怎么做?
编辑:我需要一个代码结构,它允许我为每个目录/文件/循环运行多行代码。对不起,如果我不清楚。
解决方案:我最初尝试:
find . -type d | while read DIR
do
mkdir -p "${OUTPATH}${DIR}"
echo Created $DIR
done
Run Code Online (Sandbox Code Playgroud)
这在大多数情况下运行良好。然而,我后来发现,由于管道导致 while 循环在子 shell 中运行,循环中设置的任何变量后来都不可用,这使得实现错误计数器变得非常困难。我的最终解决方案(来自SO 上的这个答案):
while read DIR
do
mkdir -p "${OUTPATH}${DIR}"
echo Created $DIR
done < <(find . -type d)
Run Code Online (Sandbox Code Playgroud)
这稍后允许我有条件地增加循环中的变量,这些变量将在脚本中稍后保持可用。
Den*_*son 11
您需要将其管道find
化为while
循环。
find ... | while read -r dir
do
something with "$dir"
done
Run Code Online (Sandbox Code Playgroud)
此外,-printf
在这种情况下您不需要使用。
如果您愿意,您可以通过使用空字节分隔符(这是唯一不能出现在 *nix 文件路径中的字符)来针对名称中包含换行符的文件进行此证明:
find ... -print0 | while read -d '' -r dir
do
something with "$dir"
done
Run Code Online (Sandbox Code Playgroud)
您还会发现使用$()
而不是反引号更通用和更容易。它们可以更轻松地嵌套,并且可以更轻松地进行引用。这个人为的例子将说明以下几点:
echo "$(echo "$(echo "hello")")"
Run Code Online (Sandbox Code Playgroud)
尝试用反引号做到这一点。
请参阅我几天前写的这个答案,以获取处理带空格的文件名的脚本示例。
有一种稍微复杂(但更简洁)的方法来实现你想要做的事情:
find . -type d -print0 | xargs -0 -I {} mkdir -p ../theredir/{}
Run Code Online (Sandbox Code Playgroud)
-print0
告诉 find 用 null 分隔参数;-0 到 xargs 告诉它期待由空值分隔的参数。这意味着它可以很好地处理空格。
-I {}
告诉 xargs{}
用文件名替换字符串。这也意味着每个命令行只应使用一个文件名(xargs 通常会填充尽可能多的内容)
其余的应该是显而易见的。
您遇到的问题是 for 语句将 find 作为单独的参数进行响应。空格分隔符。您需要使用 bash 的 IFS 变量来不分割空间。
这是一个解释如何执行此操作的链接。
IFS 内部变量
解决此问题的一种方法是更改 Bash 的内部 IFS(内部字段分隔符)变量,以便它通过除默认空格(空格、制表符、换行符)以外的其他内容(在本例中为逗号)来拆分字段。
#!/bin/bash
IFS=$';'
for I in `find -type d -printf \"%P\"\;`
do
echo "== $I =="
done
Run Code Online (Sandbox Code Playgroud)
将您的 find 设置为在 %P 之后输出您的字段分隔符并适当地设置您的 IFS。我选择了分号,因为它极不可能在您的文件名中找到。
另一种选择是直接从 find 调用 mkdir-exec
是否可以完全跳过 for 循环。那是如果您不需要进行任何额外的解析。
归档时间: |
|
查看次数: |
16137 次 |
最近记录: |