如何在 xargs-command 中使用通配符?

n.s*_*.st 11 linux bash xargs wildcards

我有一个包含编号文件的目录,例如 1_foo.txt 2_bar.asc 13_test.png,并希望使用尽可能简单的 bash 命令将它们移动到单独的目录(例如 1、2 和 13)中。

创建编号目录很容易:

mkdir $(seq 1 15)
Run Code Online (Sandbox Code Playgroud)

我还想出了一个命令来将文件复制到各自的目录中:

seq 15 -1 1 | xargs -I@ mv @_* @
Run Code Online (Sandbox Code Playgroud)

但是,这不起作用,因为 * 与 xargs 一起使用时被解释为普通字符,给我这样的错误:“mv: File '15_*' not found.”。

有什么简单的方法可以在 xargs 调用的命令中使用 * 作为通配符吗?

Sco*_*ott 26

你非常接近。

seq 15 -1 1 | xargs -I@ sh -c 'mv @_* @'
Run Code Online (Sandbox Code Playgroud)

您需要将 的解释(扩展)延迟*@发生替换之后。(但你已经明白这就是问题所在,对吗?)

有人建议我永远不要将未知文件名(或其他替换字符串)直接嵌入到 shell 命令行中。上面的示例可能相当安全,因为您知道字符串将是什么 — 1514、... 321。但是将上面的示例用作更复杂命令的模板可能很危险。更安全的安排是

seq 15 -1 1 | xargs -I@ sh -c 'mv -- "$1"_* "$1"' x-sh @
Run Code Online (Sandbox Code Playgroud)

wherex-sh是一个半任意字符串,用于标记调用的 shell 发出的任何错误消息。这等效于我的第一个示例,不同之处在于,它不是将字符串(由 表示@)直接嵌入到 shell 命令中,而是通过将@用作 shell 的参数来注入它们,然后将它们引用为"$1"


PS 您建议seq反向运行命令 ( seq 15 -1 1, 生成1514, ..., 3, 2,1 而不是1, 2, 3, ..., 14, 15) 并且没有人提到它。如果您的文件名像1foo.txt2bar.asc、 和13test.png等(在数字之后出现各种字符,而不是总是_),这将是答案的重要部分。在这种情况下,命令将是mv "$1"* "$1"(没有_),而且,如果你这样做1,然后再命令mv 1* 1 将横扫了所有的10quick*11brown*12fox*,等文件,随着1foo*文件。但

seq 1 15 | xargs -I@ sh -c 'mv -- "$1"_* "$1"' x-sh @
Run Code Online (Sandbox Code Playgroud)

应该是安全的。

PPSseq命令不是由 POSIX 指定的。壳中的大括号扩展也不是。一个POSIX兼容的解决方案可通过将构建grawity的这个问题的答案此其他答案亚当·卡茨

i=1
while [ "$i" -le 15 ]
do
    mv -- "${i}"_* "$i"
    i=$((i+1))
done
Run Code Online (Sandbox Code Playgroud)

PPPS 当您知道文件名以字母数字字符(即字母和数字)开头时,这并不重要,但在更一般的情况下,您应该--在命令名和参数之间使用。这改进了以破折号开头的文件名的处理。该 --告诉命令来治疗参数(文件名) 作为 参数。  没有它,这样的参数可能会被视为选项字符串。


use*_*686 6

只是不要xargs用于那个。使用for循环:

for i in $(seq 1 15); do
    mv ${i}_* $i
done
Run Code Online (Sandbox Code Playgroud)

更好的是使用大括号扩展而不是seq

mkdir {1..15}

for i in {1..15}; do
    mv ${i}_* $i
done
Run Code Online (Sandbox Code Playgroud)