如何在xargs -0之后执行多个命令?

发布于 2024-12-05 17:49:14 字数 287 浏览 1 评论 0 原文

find . -name "filename including space" -print0 | xargs -0 ls -aldF > log.txt
find . -name "filename including space" -print0 | xargs -0 rm -rdf

是否可以将这两个命令合并为一个,以便只完成 1 个查找而不是 2 个查找?

我知道 xargs -I 可能有多种方法可以做到这一点,这可能会导致在处理包含空格的文件名时出现错误。非常感谢任何指导。

find . -name "filename including space" -print0 | xargs -0 ls -aldF > log.txt
find . -name "filename including space" -print0 | xargs -0 rm -rdf

Is it possible to combine these two commands into one so that only 1 find will be done instead of 2?

I know for xargs -I there may be ways to do it, which may lead to errors when proceeding filenames including spaces. Any guidance is much appreciated.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

2024-12-12 17:49:14
find . -name "filename including space" -print0 | 
  xargs -0 -I '{}' sh -c 'ls -aldF {} >> log.txt; rm -rdf {}'

刚才遇到了这个问题,我们可以减少调用 shell 的频率:

find . -name "filename including space" -print0 | 
  xargs -0 sh -c '
      for file; do
          ls -aldF "$file" >> log.txt
          rm -rdf "$file"
      done
  ' sh

结尾的“sh”在 shell 中变成 $0。 xargs 将文件(从 find 返回)作为命令行参数提供给 shell:我们使用 for 循环迭代它们。

find . -name "filename including space" -print0 | 
  xargs -0 -I '{}' sh -c 'ls -aldF {} >> log.txt; rm -rdf {}'

Ran across this just now, and we can invoke the shell less often:

find . -name "filename including space" -print0 | 
  xargs -0 sh -c '
      for file; do
          ls -aldF "$file" >> log.txt
          rm -rdf "$file"
      done
  ' sh

The trailing "sh" becomes $0 in the shell. xargs provides the files (returrned from find) as command line parameters to the shell: we iterate over them with the for loop.

锦上情书 2024-12-12 17:49:14

如果您只是想避免多次执行find,则可以在find之后立即执行tee,从而保存 find 输出到文件,然后执行以下行:

find . -name "filename including space" -print0 | tee my_teed_file | xargs -0 ls -aldF > log.txt
cat my_teed_file | xargs -0 rm -rdf 

完成同一件事的另一种方法(如果确实是您想要完成的事情)是存储 find 的输出> 在一个变量中(假设它不是TB 数据):

founddata=`find . -name "filename including space" -print0`
echo "$founddata" | xargs -0 ls -aldF > log.txt
echo "$founddata" | xargs -0 rm -rdf

If you're just wanting to avoid doing the find multiple times, you could do a tee right after the find, saving the find output to a file, then executing the lines as:

find . -name "filename including space" -print0 | tee my_teed_file | xargs -0 ls -aldF > log.txt
cat my_teed_file | xargs -0 rm -rdf 

Another way to accomplish this same thing (if indeed it's what you're wanting to accomplish), is to store the output of the find in a variable (supposing it's not TB of data):

founddata=`find . -name "filename including space" -print0`
echo "$founddata" | xargs -0 ls -aldF > log.txt
echo "$founddata" | xargs -0 rm -rdf
爱已欠费 2024-12-12 17:49:14

我相信现在所有的答案都给出了解决这个问题的正确方法。我尝试了 Jonathan 的两种解决方案和 Glenn 的方法,所有这些方法在我的 Mac OS X 上都效果很好。 mouviciel 的方法在我的操作系统上不起作用,可能是由于某些配置原因。我认为这与乔纳森的第二种方法类似(我可能是错的)。

正如格伦方法的评论中提到的,需要进行一些调整。所以这是我尝试过的命令,它运行得非常好,仅供参考:

find . -name "filename including space" -print0 | 
xargs -0 -I '{}' sh -c 'ls -aldF {} | tee -a log.txt ; rm -rdf {}'

或者按照格伦的建议更好:

find . -name "filename including space" -print0 | 
xargs -0 -I '{}' sh -c 'ls -aldF {} >> log.txt ; rm -rdf {}'

I believe all these answers by now have given out the right ways to solute this problem. And I tried the 2 solutions of Jonathan and the way of Glenn, all of which worked great on my Mac OS X. The method of mouviciel did not work on my OS maybe due to some configuration reasons. And I think it's similar to Jonathan's second method (I may be wrong).

As mentioned in the comments to Glenn's method, a little tweak is needed. So here is the command I tried which worked perfectly FYI:

find . -name "filename including space" -print0 | 
xargs -0 -I '{}' sh -c 'ls -aldF {} | tee -a log.txt ; rm -rdf {}'

Or better as suggested by Glenn:

find . -name "filename including space" -print0 | 
xargs -0 -I '{}' sh -c 'ls -aldF {} >> log.txt ; rm -rdf {}'
不疑不惑不回忆 2024-12-12 17:49:14

只要文件名中没有换行符,GNU Parallel 就不需要 -print0:

find . -name "My brother's 12\" records" | parallel ls {}\; rm -rdf {} >log.txt

观看介绍视频以了解更多信息:http://www.youtube.com/watch?v=OpaiGYxkSuQ

As long as you do not have newline in your filenames, you do not need -print0 for GNU Parallel:

find . -name "My brother's 12\" records" | parallel ls {}\; rm -rdf {} >log.txt

Watch the intro video to learn more: http://www.youtube.com/watch?v=OpaiGYxkSuQ

浅忆流年 2024-12-12 17:49:14

只是 xargs 方法的一种变体,没有可怕的 -print0xargs -0,这就是我的做法:

ls -1 *.txt  | xargs --delimiter "\n" --max-args 1 --replace={} sh -c 'cat {}; echo "\n"'

脚注:

  • 是的,我知道换行符可以出现在文件名中,但头脑正常的人会这样做。
  • xargs 有简短的选项,但为了读者的理解,我使用了较长的选项。
  • 当我想要非递归行为时,我会使用 ls -1 ,而不是使用更冗长的 find -maxdepth 1 -iname "*.txt" 。

Just a variation of the xargs approach without that horrible -print0 and xargs -0, this is how I would do it:

ls -1 *.txt  | xargs --delimiter "\n" --max-args 1 --replace={} sh -c 'cat {}; echo "\n"'

Footnotes:

  • Yes I know newlines can appear in filenames but who in their right minds would do that
  • There are short options for xargs but for the reader's understanding I've used the long ones.
  • I would use ls -1 when I want non-recursive behavior rather than find -maxdepth 1 -iname "*.txt" which is a bit more verbose.
烟酉 2024-12-12 17:49:14

您可以在 find 之后使用 for 而不是 xargs 执行多个命令:

IFS=

IFS 定义内部字段分隔符,它默认为<空格><制表符><换行>。如果您的文件名可能包含空格,最好按照上面的方法重新定义它。

\n' for F in `find . -name "filename including space"` do ls -aldF $F > log.txt rm -rdf $F done

IFS 定义内部字段分隔符,它默认为<空格><制表符><换行>。如果您的文件名可能包含空格,最好按照上面的方法重新定义它。

You can execute multiple commands after find using for instead of xargs:

IFS=

The IFS defines the Internal Field Separator, which defaults to <space><tab><newline>. If your filenames may contain spaces, it is better to redefine it as above.

\n' for F in `find . -name "filename including space"` do ls -aldF $F > log.txt rm -rdf $F done

The IFS defines the Internal Field Separator, which defaults to <space><tab><newline>. If your filenames may contain spaces, it is better to redefine it as above.

豆芽 2024-12-12 17:49:14

我迟到了,但这里没有介绍另一种解决方案:用户定义的函数。将多条指令放在一行上很不方便,并且难以阅读/维护。上面的 for 循环避免了这种情况,但有可能超出命令行长度。

这是另一种方法(未经测试)。

function processFiles {
  ls -aldF "$@"
  rm -rdf "$@"
}
export -f processFiles

find . -name "filename including space"` -print0 \
  | xargs -0 bash -c processFiles dummyArg > log.txt

除了“dummyArg”之外,这非常简单,它给了我很多悲伤。以这种方式运行 bash 时,会读取参数

"$0" "$1" "$2"  ....

而不是预期的

"$1" "$2" "$3"    ....

参数由于 processFiles{} 期望第一个参数为“$1”,因此我们必须在“”中插入一个虚拟值0 美元”

Footnontes:

  1. 我正在使用 bash 语法的一些元素(例如“export -f”),但我相信这会适应其他 shell。
  2. 我第一次尝试这个时,我没有添加虚拟参数。相反,我将“$0”添加到函数内的参数行中(例如 ls -aldf "$0" "$@" )。坏主意。
    除了风格问题之外,当“find”命令不返回任何内容时,它就会中断。在这种情况下,$0 设置为“bash”,使用虚拟参数可以避免所有这些。

I'm late to the party, but there is one more solution that wasn't covered here: user-defined functions. Putting multiple instructions on one line is unwieldy, and can be hard to read/maintain. The for loop above avoids that, but there is the possibility of exceeding the command line length.

Here's another way (untested).

function processFiles {
  ls -aldF "$@"
  rm -rdf "$@"
}
export -f processFiles

find . -name "filename including space"` -print0 \
  | xargs -0 bash -c processFiles dummyArg > log.txt

This is pretty straightforward except for the "dummyArg" which gave me plenty of grief. When running bash in this way, the arguments are read into

"$0" "$1" "$2"  ....

instead of the expected

"$1" "$2" "$3"    ....

Since processFiles{} is expecting the first argument to be "$1", we have to insert a dummy value into "$0".

Footnontes:

  1. I am using some elements of bash syntax (e.g. "export -f"), but I believe this will adapt to other shells.
  2. The first time I tried this, I didn't add a dummy argument. Instead I added "$0" to the argument lines inside my function ( e.g. ls -aldf "$0" "$@" ). Bad idea.
    Aside from stylistic issues, it breaks when the "find" command returns nothing. In that case, $0 is set to "bash", Using the dummy argument instead avoids all of this.
如何视而不见 2024-12-12 17:49:14

另一个解决方案:

find . -name "filename including space" -print0 \
| xargs -0 -I FOUND echo "$(ls -aldF FOUND > log.txt ; rm -rdf FOUND)"

Another solution:

find . -name "filename including space" -print0 \
| xargs -0 -I FOUND echo "$(ls -aldF FOUND > log.txt ; rm -rdf FOUND)"
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文