[英]Double quotes vs asterisk filename expansion in Bash
在目录~/temp/a/foo/
和~/temp/b/foo foo/
我有一些名为bar1
, bar2
, bar bar1
, bar bar2
等的文件。
我正在尝试编写一行Bash,将包含“foo”的目录中的所有这些文件作为名称的最后一部分复制到相应“foo”文件夹上方的文件夹中。
只要文件名中没有空格,这是一项简单的任务,但在处理foo foo
目录时,以下两个命令会失败:
for dir in `find . -type d -name '*foo'` ; do cp $dir/* "$(echo $dir|sed 's_foo__g')" ; done
( cp
命令无法将"foo foo"
的最后一个foo
视为同一目录名的一部分。)
for dir in `find . -type d -name '*foo'` ; do cp "$dir/*" "$(echo $dir|sed 's_foo__g')" ; done
( "$dir/*"
未展开。)
尝试将$dir/*
替换$dir/*
"$(echo $dir/*)"
尝试更不成功。
是否有一种简单的方法来扩展$dir/*
以便cp
理解?
for
循环不仅错误 - sed
也不适合这项工作。
while IFS= read -r -d '' dir; do
cp "$dir" "${dir/foo/}"
done < <(find . -type d -name '*foo' -print0)
在find
(和IFS= read -r -d ''
)上使用-print0
可确保带有换行符的文件名不会弄乱你。
使用< <(...)
构造确保如果循环内部设置变量,更改目录状态或执行类似的操作,那些更改将继续存在(管道的右侧位于bash的子shell中,如此管道进入while循环意味着在while循环中对shell的状态所做的任何更改都将在其退出时被丢弃。
使用${dir/foo/}
比调用sed
更有效,因为它在bash内部执行字符串替换。
这里的问题是不是与cp
,而是for
,因为默认情况下它被分割的话你的输出壳层的,而不是由目录名。
一个懒惰的解决方法是使用while
而是逐行处理目录列表,如下所示:
find . -type d -name '*foo' | while read dir; do cp "$dir"/* "$(echo $dir | sed 's_foo__g')" ; done
这应该可以解决你的空间问题,但这绝不是一个万无一失的解决方案。
请参阅Charles Duffy的答案,以获得更准确的解决方案。
将~/temp/b/foo foo/
重命名为没有空格的东西,例如~/temp/b/foo_foo/
并做你想要再做的事情。 之后,如果你真的需要,你可以将它重命名为原始空间。 BTW。 我自己从不使用包含空格的文件名,只是为了避免像你现在面临的那样复杂化。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.