我试图将所有以“m”开头的文件重命名为相同的名称,除了第一个字符(或本例中的“m”)被删除。
我的策略是:
- 列出所有文件,其中
ls
- 过滤出我想要的,
egrep
- 在我想要的字符串旁边生成我不想要的字符串,用空格分隔,
awk
例如,mfoo foo
- 送入
xargs
至mv mfoo foo
一些问题:
- 这是一个好的策略吗?
- 什么是更好的?
我陷入了第三步,下面是我解决这个问题的方法。
我正在以下目录中工作:
$ find .
.
./cat
./mbar
./mbaz
./mfoo
我能够快速得到 1-2:
$ ls | egrep '^m'
mbar
mbaz
mfoo
第3步比较困难。我曾经gsub
生成我想要的第二个字符串,但我不确定如何“将其与用空格分隔的原始值粘在一起”:
$ ls | egrep '^m' | awk '{ gsub(/^./, ""); print }'
bar
baz
foo
第 4 步对我来说很有意义,尽管我不确定如何完成第 3 步,所以我还无法完成它。下面是我认为它应该如何工作的一个例子:
$ echo mfoo foo | xargs mv
$ find .
.
./cat
./foo
./mbar
./mbaz
我想我已经很接近了,我只需要找出如何保存旧值并将其打印在 gsubed 值旁边。我尝试过以下小示例,但它不起作用:
$ echo mfoo | awk '
pipe quote> { old = $0 }
pipe quote> { new = gsub(/^./, "") }
pipe quote> { print $old " " $new }'
awk: illegal field $(mfoo), name "old"
input record number 1, file
source line number 4
- 如何替换
$0
但保存旧值? - 为什么我会收到此错误?
答案1
这应该处理整个操作:
for file in m*; do mv "${file}" "${file#m}"; done
在运行之前,请先检查一下
for file in m*; do echo mv "${file}" "${file#m}"; done
这将m*
glob 用于步骤 1 和 2,然后${file#m}
(从 的开头删除“m” ${file}
)用于步骤 3,最后使用循环用于步骤 4。
要回答您的 AWK 问题,您可以这样处理:
echo mfoo | awk '{ print $0, substr($0, 2) }'
AWK 变量不使用$
,仅适用于字段;这就是您的错误的来源:AWK 将其理解$old
为“根据 的值编号的字段的值old
”。如果将命令放在一个块中(假设它们具有相同的模式),那么也更容易阅读。修复你的脚本给出
echo mfoo | awk '{ old = $0; gsub(/^./, ""); print old, $0 }'
答案2
ls | egrep '^m' | awk '{ x=$0; gsub(/^./, ""); $0 = x " " $0 }1' | xargs -l -t mv
Posix-莱实现是通过以下-L
选项xargs
:
ls | egrep '^m' | awk '{ x=$0; gsub(/^./, ""); $0 = x " " $0 }1' | xargs -L 1 -t mv
ls | egrep '^m' | awk '{ x=$0; gsub(/^./, ""); print x, $0 }' | xargs -L 1 -t mv
基于什么我回答对于您之前关于 的询问xargs
,我们可以在这个例子中充分利用所学到的知识。
我稍微修改了你的awk
代码:它保留了原始行($0
),因为gsub
func 会破坏它。然后,我们将旧的和新的放在一起,以获得我们想要发送到的行xargs
,然后mv
使用正确的参数调用以实现重命名。
答案3
更好的策略是使用rename
命令。
请注意,此命令的确切语法是特定于发行版的,请参阅man
您的特定发行版版本的页面。例如,在 Ubuntu 上,它具有 Perl 实现rename
,您可以使用正则表达式:
rename -nono 's/^m//' m*
注意:删除该-nono
标志才能实际执行重命名。