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

时间:2021-01-27 00:11:40

I know you can do it with a find, but is there a way to send the output of ls to mv in the unix command line?

我知道你可以用find来做,但有没有办法在unix命令行中将ls的输出发送到mv?

12 个解决方案

#1


One way is with backticks:

一种方法是使用反引号:

mv `ls *.boo` subdir

Edit: however, this is fragile and not recommended -- see @lhunath's asnwer for detailed explanations and recommendations.

编辑:但是,这是脆弱的,不推荐 - 请参阅@ lhunath的asnwer以获取详细的解释和建议。

#2


ls is a tool used to DISPLAY some statistics about filenames in a directory.

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

It is not a tool you should use to enumerate them and pass them to another tool for using it there. Parsing ls is almost always the wrong thing to do, and it is bugged in many ways.

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

For a detailed document on the badness of parsing ls, which you should really go read, check out: http://mywiki.wooledge.org/ParsingLs

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

Instead, you should use either globs or find, depending on what exactly you're trying to achieve:

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

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

The main source of badness of parsing ls is that ls dumps all filenames into a single string of output, and there is no way to tell the filenames apart from there. For all you know, the entire ls output could be one single filename!

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

The secondary source of badness of parsing ls comes from the broken way in which half the world uses bash. They think for magically does what they would like it to do when they do something like:

解析ls的第二个坏处来源于世界上一半使用bash的破碎方式。他们认为,当他们做类似的事情时,他们会神奇地做他们希望它做的事情:

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

for is a bash builtin that iterates over arguments. And $(ls) takes the output of ls and cuts it apart into arguments wherever there are spaces, newlines or tabs. Which basically means, you're iterating over words, not over filenames. Even worse, you're asking bask to take each of those mutilated filename words and then treat them as globs that may match filenames in the current directory. So if you have a filename which contains a word which happens to be a glob that matches other filenames in the current directory, that word will disappear and all those matching filenames will appear in its stead!

for是一个bash内置迭代参数。并且$(ls)获取ls的输出并将其分成参数,只要有空格,换行符或制表符。这基本上意味着,你是在迭代单词,而不是文件名。更糟糕的是,你要求bask获取每个残缺的文件名,然后将它们视为可能与当前目录中的文件名匹配的globs。因此,如果您的文件名包含一个恰好是与当前目录中其他文件名匹配的glob的单词,那么该单词将会消失,所有匹配的文件名将会出现!

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

#3


Not exactly sure what you're trying to achieve here, but here's one possibility:

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

The "xargs" part is the important piece everything else is just setup. The effect of this is to take everything that "ls" outputs and add a ".txt" extension to it.

“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
$

Something like this could also be achieved by:

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

$ 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
$

I sort of like the second way better. I can NEVER remember how xargs works without reading the man page or going to my "cute tricks" file.

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

Hope this helps.

希望这可以帮助。

#4


Check out find -exec {} as it might be a better option than ls but it depends on what you're trying to achieve.

查看找到-exec {}因为它可能是比ls更好的选择,但这取决于你想要实现的目标。

#5


None of the answers so far are safe for filenames with spaces in them. Try this:

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

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

You can of course use any glob pattern you like in place of *.

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

#6


You shouldn't use the output of ls as the input of another command. Files with spaces in their names are difficult as is the inclusion of ANSI escape sequences if you have:

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

alias ls-'ls --color=always'

for example.

Always use find or xargs (with -0) or globbing.

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

Also, you didn't say whether you want to move files or rename them. Each would be handled differently.

此外,您没有说明是要移动文件还是重命名文件。每个都将以不同方式处理。

edit: added -0 to xargs (thanks for the reminder)

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

#7


Backticks work well, as others have suggested. See xargs, too. And for really complicated stuff, pipe it into sed, make the list of commands you want, then run it again with the output of sed piped into sh.

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

Here's an example with find, but it works fine with ls, too:

这是find的一个例子,但它也适用于ls:

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

#8


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

"Useless use of ls", but should work. By specifying the full path to ls(1) you avoid *es with aliasing of ls(1) mentioned in some of the previous posts. The tr(1) command together with "xargs -0" makes the command work with filenames containing (ugh) whitespace. It won't work with filenames containing newlines, but having filenames like that in the file system is to ask for trouble, so it probably won't be a big problem. But filenames with newlines could exist, so a better solution would be to use "find -print0":

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

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

#9


Just use find or your shells globing!

只需使用find或你的炮弹!

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

..or..

mv * /tmp/blah/

You don't have to worry about colour in the ls output, or other piping strangeness - Linux allows basically any characters in the filename except a null byte.. For example:

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

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

..but find works perfectly:

..但找到完美的工作:

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

#10


For more complicated cases (often in a script), using bash arrays to build up the argument list can be very useful. One can create an array and push to it with the appropriate conditional logic. For example:

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

Following up on @lhunath's recommendation to use globs or find, push files matching a glob pattern to the array:

按照@ lhunath建议使用globs或find,将匹配glob模式的文件推送到数组:

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

Push files matching a find to the array: https://*.com/a/23357277/430128.

将匹配查找的文件推送到阵列:https://*.com/a/23357277/430128。

Add additional arguments as necessary:

根据需要添加其他参数:

myargs+=("Some directory")

Use myargs in the invocation of a command like mv:

在调用像mv这样的命令时使用myargs:

mv "${myargs[@]}"

Note the quoting of the array myargs to pass array elements with spaces correctly.

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

#11


You surround the ls with back quotes and put it after the mv, so like this...

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

mv `ls` somewhere/

But keep in mind that if any of your file names have spaces in them it won't work very well.

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

Also it would be simpler to just do something like this: mv filepattern* somewhere/

也可以更简单地做这样的事情:mv filepattern * somewhere /

#12


#!/bin/bash

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

else, it's the find solution by sybreon, and as suggested NOT the green mv ls solution.

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

#1


One way is with backticks:

一种方法是使用反引号:

mv `ls *.boo` subdir

Edit: however, this is fragile and not recommended -- see @lhunath's asnwer for detailed explanations and recommendations.

编辑:但是,这是脆弱的,不推荐 - 请参阅@ lhunath的asnwer以获取详细的解释和建议。

#2


ls is a tool used to DISPLAY some statistics about filenames in a directory.

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

It is not a tool you should use to enumerate them and pass them to another tool for using it there. Parsing ls is almost always the wrong thing to do, and it is bugged in many ways.

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

For a detailed document on the badness of parsing ls, which you should really go read, check out: http://mywiki.wooledge.org/ParsingLs

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

Instead, you should use either globs or find, depending on what exactly you're trying to achieve:

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

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

The main source of badness of parsing ls is that ls dumps all filenames into a single string of output, and there is no way to tell the filenames apart from there. For all you know, the entire ls output could be one single filename!

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

The secondary source of badness of parsing ls comes from the broken way in which half the world uses bash. They think for magically does what they would like it to do when they do something like:

解析ls的第二个坏处来源于世界上一半使用bash的破碎方式。他们认为,当他们做类似的事情时,他们会神奇地做他们希望它做的事情:

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

for is a bash builtin that iterates over arguments. And $(ls) takes the output of ls and cuts it apart into arguments wherever there are spaces, newlines or tabs. Which basically means, you're iterating over words, not over filenames. Even worse, you're asking bask to take each of those mutilated filename words and then treat them as globs that may match filenames in the current directory. So if you have a filename which contains a word which happens to be a glob that matches other filenames in the current directory, that word will disappear and all those matching filenames will appear in its stead!

for是一个bash内置迭代参数。并且$(ls)获取ls的输出并将其分成参数,只要有空格,换行符或制表符。这基本上意味着,你是在迭代单词,而不是文件名。更糟糕的是,你要求bask获取每个残缺的文件名,然后将它们视为可能与当前目录中的文件名匹配的globs。因此,如果您的文件名包含一个恰好是与当前目录中其他文件名匹配的glob的单词,那么该单词将会消失,所有匹配的文件名将会出现!

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

#3


Not exactly sure what you're trying to achieve here, but here's one possibility:

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

The "xargs" part is the important piece everything else is just setup. The effect of this is to take everything that "ls" outputs and add a ".txt" extension to it.

“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
$

Something like this could also be achieved by:

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

$ 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
$

I sort of like the second way better. I can NEVER remember how xargs works without reading the man page or going to my "cute tricks" file.

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

Hope this helps.

希望这可以帮助。

#4


Check out find -exec {} as it might be a better option than ls but it depends on what you're trying to achieve.

查看找到-exec {}因为它可能是比ls更好的选择,但这取决于你想要实现的目标。

#5


None of the answers so far are safe for filenames with spaces in them. Try this:

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

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

You can of course use any glob pattern you like in place of *.

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

#6


You shouldn't use the output of ls as the input of another command. Files with spaces in their names are difficult as is the inclusion of ANSI escape sequences if you have:

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

alias ls-'ls --color=always'

for example.

Always use find or xargs (with -0) or globbing.

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

Also, you didn't say whether you want to move files or rename them. Each would be handled differently.

此外,您没有说明是要移动文件还是重命名文件。每个都将以不同方式处理。

edit: added -0 to xargs (thanks for the reminder)

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

#7


Backticks work well, as others have suggested. See xargs, too. And for really complicated stuff, pipe it into sed, make the list of commands you want, then run it again with the output of sed piped into sh.

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

Here's an example with find, but it works fine with ls, too:

这是find的一个例子,但它也适用于ls:

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

#8


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

"Useless use of ls", but should work. By specifying the full path to ls(1) you avoid *es with aliasing of ls(1) mentioned in some of the previous posts. The tr(1) command together with "xargs -0" makes the command work with filenames containing (ugh) whitespace. It won't work with filenames containing newlines, but having filenames like that in the file system is to ask for trouble, so it probably won't be a big problem. But filenames with newlines could exist, so a better solution would be to use "find -print0":

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

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

#9


Just use find or your shells globing!

只需使用find或你的炮弹!

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

..or..

mv * /tmp/blah/

You don't have to worry about colour in the ls output, or other piping strangeness - Linux allows basically any characters in the filename except a null byte.. For example:

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

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

..but find works perfectly:

..但找到完美的工作:

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

#10


For more complicated cases (often in a script), using bash arrays to build up the argument list can be very useful. One can create an array and push to it with the appropriate conditional logic. For example:

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

Following up on @lhunath's recommendation to use globs or find, push files matching a glob pattern to the array:

按照@ lhunath建议使用globs或find,将匹配glob模式的文件推送到数组:

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

Push files matching a find to the array: https://*.com/a/23357277/430128.

将匹配查找的文件推送到阵列:https://*.com/a/23357277/430128。

Add additional arguments as necessary:

根据需要添加其他参数:

myargs+=("Some directory")

Use myargs in the invocation of a command like mv:

在调用像mv这样的命令时使用myargs:

mv "${myargs[@]}"

Note the quoting of the array myargs to pass array elements with spaces correctly.

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

#11


You surround the ls with back quotes and put it after the mv, so like this...

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

mv `ls` somewhere/

But keep in mind that if any of your file names have spaces in them it won't work very well.

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

Also it would be simpler to just do something like this: mv filepattern* somewhere/

也可以更简单地做这样的事情:mv filepattern * somewhere /

#12


#!/bin/bash

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

else, it's the find solution by sybreon, and as suggested NOT the green mv ls solution.

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