如何替换“$0”但保存旧值?

如何替换“$0”但保存旧值?

我试图将所有以“m”开头的文件重命名为相同的名称,除了第一个字符(或本例中的“m”)被删除。

我的策略是:

  1. 列出所有文件,其中ls
  2. 过滤出我想要的,egrep
  3. 在我想要的字符串旁边生成我不想要的字符串,用空格分隔,awk例如,mfoo foo
  4. 送入xargsmv 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),因为gsubfunc 会破坏它。然后,我们将旧的和新的放在一起,以获得我们想要发送到的行xargs,然后mv使用正确的参数调用以实现重命名。

答案3

更好的策略是使用rename命令。

请注意,此命令的确切语法是特定于发行版的,请参阅man您的特定发行版版本的页面。例如,在 Ubuntu 上,它具有 Perl 实现rename,您可以使用正则表达式:

rename -nono 's/^m//' m*

注意:删除该-nono标志才能实际执行重命名。

相关内容