你如何将ls的输出发送到mv?

时间:2009-06-02 02:45:17

标签: bash command-line

我知道您可以使用find执行此操作,但有没有办法在unix命令行中将ls的输出发送到mv

12 个答案:

答案 0 :(得分:74)

ls是一个用于显示某些目录中文件名统计信息的工具。

一个工具,您应该使用它来枚举它们并将它们传递给另一个工具以便在那里使用它。解析ls 几乎总是做错事,而且它在很多方面都有问题。

有关解析ls的难度的详细文档,您应该真的去阅读,请查看: http://mywiki.wooledge.org/ParsingLs

相反,您应该使用globs或find,具体取决于您要实现的目标:

mv * /foo
find . -exec mv {} /foo \;

解析ls的不良主要原因是ls将所有文件名转储到单个输出字符串中,并且无法将文件名分开。如您所知,整个ls输出可以是一个文件名!

解析ls的不良后果来自于世界上一半使用bash的破碎方式。他们认为for在他们做类似的事情时会神奇地做他们希望做的事情:

for file in `ls`  # Never do this!
for file in $(ls) # Exactly the same thing.

for是一个bash内置迭代参数。 $(ls)获取ls的输出,并将其分为参数,只要有spacesnewlinestabs。这基本上意味着,您正在迭代单词,而不是文件名。更糟糕的是,你要求bask取出每个残缺的文件名,然后将它们视为可能与当前目录中的文件名匹配的globs。因此,如果你有一个文件名,其中包含一个与当前目录中的其他文件名匹配的字符串,则该字将消失,所有匹配的文件名将会出现![/ p>

mv `ls` /foo      # Exact same badness as the ''for'' thing.

答案 1 :(得分:21)

一种方法是使用反引号:

mv `ls *.boo` subdir

修改:但是,这是脆弱的不是推荐 - 请参阅@ lhunath的asnwer以获取详细说明和建议。

答案 2 :(得分:5)

不完全确定你在这里想要达到的目标,但这里有一种可能性:

“xargs”部分是其他一切设置的重要部分。这样做的结果是获取“ls”输出的所有内容并为其添加“.txt”扩展名。

$ mkdir xxx  # 
$ cd xxx
$ touch a b c x y z
$ ls
a  b  c  x  y  z
$ ls | xargs -Ifile mv file file.txt
$ ls
a.txt  b.txt  c.txt  x.txt  y.txt  z.txt
$

这样的事情也可以通过以下方式实现:

$ touch a b c x y z
$ for i in `ls`;do mv $i ${i}.txt; done
$ ls
a.txt  b.txt  c.txt  x.txt  y.txt  z.txt
$

我有点像第二种方式更好。我永远不会记得 xargs 是如何工作的,无需阅读手册页或转到我的“可爱技巧”文件。

希望这有帮助。

答案 3 :(得分:5)

查看find -exec {}因为它可能比ls更好,但这取决于您要实现的目标。

答案 4 :(得分:4)

到目前为止,没有任何答案对于包含空格的文件名是安全的。试试这个:

for i in *; do mv "$i" some_dir/; done

您当然可以使用任何您喜欢的glob模式代替*

答案 5 :(得分:1)

您不应将ls的输出用作另一个命令的输入。名称中包含空格的文件很难,如果您有以下内容,则包含ANSI转义序列:

alias ls-'ls --color=always'

例如。

始终使用find或xargs(使用-0)或globbing。

此外,您没有说明是要移动文件还是重命名文件。每种方法都会有不同的处理方式。

编辑:将-0添加到xargs(感谢提醒)

答案 6 :(得分:0)

正如其他人所建议的那样,反引号效果很好。也见xargs。对于非常复杂的东西,将它输入sed,制作你想要的命令列表,然后再次运行它,并将sed的输出传送到sh。

以下是find的示例,但它也适用于ls:

http://github.com/DonBranson/scripts/blob/f09d24629ab6eb3ce509d4d3078818430306b063/jarfinder.sh

答案 7 :(得分:0)

/bin/ls | tr '\n' '\0' | xargs -0 -i% mv % /path/to/destdir/

“无用的ls”,但应该有效。通过指定ls(1)的完整路径,可以避免在之前的一些帖子中提到的ls(1)别名冲突。 tr(1)命令与“xargs -0”一起使命令适用于包含(ugh)空格的文件名。它不适用于包含换行符的文件名,但在文件系统中有这样的文件名是要求麻烦,所以它可能不会是一个大问题。但是可能存在带换行符的文件名,因此更好的解决方案是使用“find -print0”:

find /path/to/srcdir -type f -print0 | xargs -0 -i% mv % dest/

答案 8 :(得分:-1)

只需使用find或你的炮弹!

find . -depth=1 -exec mv {} /tmp/blah/ \;

.. ..或

mv * /tmp/blah/

您不必担心ls输出中的颜色或其他管道奇怪 - Linux基本上允许文件名中除空字节之外的任何字符。例如:

$ touch "blah\new|
> "
$ ls | xargs file
blahnew|:                  cannot open `blahnew|' (No such file or directory)

..但找到完美的作品:

$ find . -exec file {} \;
./blah\new|
: empty

答案 9 :(得分:-1)

对于更复杂的情况(通常在脚本中),使用bash数组构建参数列表可能非常有用。可以使用适当的条件逻辑创建一个数组并推送到它。例如:

跟随@ lhunath的recommendation使用globs或find,将匹配glob模式的文件推送到数组:

myargs=()
# don't push if the glob does not match anything
shopt -s nullglob
myargs+=(myfiles*)

将匹配查找的文件推送到数组:https://stackoverflow.com/a/23357277/430128

根据需要添加其他参数:

myargs+=("Some directory")

在调用myargs之类的命令时使用mv

mv "${myargs[@]}"

注意引用数组myargs以正确传递带空格的数组元素。

答案 10 :(得分:-2)

你用背引号包围ls并把它放在mv之后,就像这样......

mv `ls` somewhere/

但请记住,如果你的任何文件名中都有空格,那么它将无法正常工作。

这样做更简单:mv filepattern* somewhere/

答案 11 :(得分:-2)

#!/bin/bash

for i in $( ls * );
do
mv $1 /backup/$1
done

否则,它是sybreon的查找解决方案,并且建议不要使用绿色mv ls解决方案。