如何在ls和mv中使用ms-dos样式的通配符?


9

我有一个来自MS-DOS背景的不幸经历-但至少这使我意识到Linux的功能强大得多。我一直在努力使Linux-Fu达到同等水平,但是使用DOS可以完成几件事,但我不确定如何最轻松地使用Linux 来完成:

重命名多个文件-使用两个通配符

c:\> dir

Directory of c:\
    file1.txt
    file2.txt
    file3.txt
    file4.txt

c:\>rename *.txt *.bak

c:\> dir

Directory of c:\
    file1.bak
    file2.bak
    file3.bak
    file4.bak

我知道我可以find -exec在这里使用,但是有可能使用较短的语法-也许mv带有一些特殊的标志或语法?我猜想关键是第二个 *通配符,因为linux的第一个不应该有问题(即我知道如何选择要使用通配符重命名的文件)

重命名单个文件-使用一个通配符

c:\> dir

Directory of c:\
    file1.txt

c:\>rename file1.txt *.bak

c:\> dir

Directory of c:\
    file1.bak

重命名冗长且笨拙的文件名时,这将特别有用。我以为也许我可以用mv file1.txt $1.bak它最终file1.txt.bak接受,但我不确定您是否可以$1使用shell命令内联引用参数。同样,在此特定情况下,ms-dos如何对*通配符进行盲目化以用作部分文件名的捕获/替换匹配也很方便。

使用通配符过滤目录列表

c:\> dir

Directory of c:\
    file1.txt
    file2.txt
    file3.txt
    file4.txt
    text.txt
    \temp       (directory) 

c:\> dir file*

Directory of c:\
    file1.txt
    file2.txt
    file3.txt
    file4.txt

c:\> t*

Directory of c:\
    text.txt
    \temp       (directory) 

我不确定执行此操作的正确语法是什么ls,或者甚至是可能的。如果我做了类似的ls t*事情,它将递归到以开头的目录t。我的解决方法是一直在使用find . --max-depth 1 -iname "t*"或类似的东西ls -al | grep t-两者都不是那么简单和简短dir t*

最后,我知道我可以设置别名以使这些长命令更短,但是我想学习一些现成的linux-fu来完成这些事情,因为有时您连接到远程系统或正在工作在新机器上。

那么,如何mvls文件使用与过去相同的方式dirrename文件?

Answers:


15

Windows cmd和POSIX Shell 之间的根本区别之一是谁负责通配符扩展。Shells在启动您要求的实际命令之前会进行所有必需的扩展。cmd 通常将通配符模式传递给未修改的命令。(我主要是说,因为我认为有例外,并且在大多数情况下都会扩展环境变量。)这使得编写一个rename可以使用与cmd非常棘手的语法相同的语法的a 。

但是有一个rename适用于Linux的Linux-具有完全不同的参数,请查看手册页(这在我的系统上有点简洁,并且rename来自util-linux我系统上的软件包,应该可以广泛使用)。您的第一个重命名将这样完成:

rename .txt .bak *.txt

请注意,shell会进行*扩展,因此rename它本身实际上认为是这样调用的:

rename .txt .bak file1.txt file2.txt file3.txt ...

因此,您可以猜测单个文件的版本:

rename .txt .bak file1.txt

如果您不想使用rename而是自己实现,则可以为此创建一个函数。假设您只想更改文件扩展名,并且要重命名单个文件,请查看以下内容:

$ function chext() {
  newext="$1"
  file="$2"
  newfile="${file%.*}$newext"
  echo mv "$file" "$newfile"
}
$ chext .csv test.txt
mv text.txt text.csv

$newfile使用子字符串删除功能构建,以去除原始扩展名,然后连接新扩展名。您可以扩展该功能以相对轻松地处理多个文件。


至于您的ls问题,请使用-d开关。这将防止ls列出目录的内容。

演示:

$ ls -al
total 536
drwx------   3 owner users 528384 Jan  7 17:29 .
drwxr-xr-x 126 owner users  12288 Jan  7 17:26 ..
-rw-r--r--   1 owner users      0 Jan  7 17:28 f1.csv
-rw-r--r--   1 owner users      0 Jan  7 17:28 f2.csv
-rw-r--r--   1 owner users      0 Jan  7 17:28 f3.csv
-rw-r--r--   1 owner users      0 Jan  7 17:28 f4.csv
drwxr-xr-x   2 owner users   4096 Jan  7 17:33 test
-rw-r--r--   1 owner users      0 Jan  7 17:27 test.csv

通配符重命名

$ rename .csv .txt f*
$ ls -al
total 536
drwx------   3 owner users 528384 Jan  7 17:34 .
drwxr-xr-x 126 owner users  12288 Jan  7 17:26 ..
-rw-r--r--   1 owner users      0 Jan  7 17:28 f1.txt
-rw-r--r--   1 owner users      0 Jan  7 17:28 f2.txt
-rw-r--r--   1 owner users      0 Jan  7 17:28 f3.txt
-rw-r--r--   1 owner users      0 Jan  7 17:28 f4.txt
drwxr-xr-x   2 owner users   4096 Jan  7 17:33 test
-rw-r--r--   1 owner users      0 Jan  7 17:27 test.csv

单文件重命名

$ rename .txt .csv f1.txt 
$ ls -al
total 536
drwx------   3 owner users 528384 Jan  7 17:34 .
drwxr-xr-x 126 owner users  12288 Jan  7 17:26 ..
-rw-r--r--   1 owner users      0 Jan  7 17:28 f1.csv
-rw-r--r--   1 owner users      0 Jan  7 17:28 f2.txt
-rw-r--r--   1 owner users      0 Jan  7 17:28 f3.txt
-rw-r--r--   1 owner users      0 Jan  7 17:28 f4.txt
drwxr-xr-x   2 owner users   4096 Jan  7 17:33 test
-rw-r--r--   1 owner users      0 Jan  7 17:27 test.csv

默认值 ls

$ ls -l t*
-rw-r--r-- 1 owner users    0 Jan  7 17:27 test.csv

test:
total 0
-rw-r--r-- 1 owner users 0 Jan  7 17:33 dont_show_me_please

ls 不检查目录

$ ls -ld t*
drwxr-xr-x 2 owner users 4096 Jan  7 17:33 test
-rw-r--r-- 1 owner users    0 Jan  7 17:27 test.csv

非常好!我想我刚刚把我的linux-fu带走了!谢谢!
cwd 2012年

在此方面有所进展的技巧(并避免陷阱):使用简单的函数或脚本来查看somefunc *.Ext如果该模式与任何文件都不匹配时执行该操作会发生什么,并使用引号进行查看以查看是否能够成功传递模式(功能之间)。安全提示:尝试进行球形/外壳扩展时不要rm在任何地方使用:-)
2012年

4

关于通配符,要记住的一件事是它们被shell扩展了。该应用程序不知道您使用通配符还是键入名称。例如,如果键入rename *.txt *.bak,则该rename命令将显示类似的信息rename file1.txt file2.txt existingfile.bak。信息不足以继续。

我将首先处理这个问题ls,因为它比较简单。如果只需要匹配的名称,则不需要ls,因为外壳程序已经在进行扩展。

echo t*

如果需要有关文件的更多信息,请将-d选项传递给ls,以告诉它不要列出目录的内容。

ls -ld t*

没有用于重命名文件的标准实用程序,因为第一个unix系统不附带一个。重命名文件的可移植方法使用循环,并且有点冗长:

for x in *.txt; do mv -- "$x" "${x%.txt}.bak"; done

有几种常用的实用程序来重命名文件,不能保证没有一个安装在给定的unix系统上,但是所有的实用程序都易于安装。这里是主要的:

  • renameutil-linux套件中提供的工具,可在每个非嵌入式Linux系统上使用(其他地方都没有)。在Debian及其衍生产品(包括Ubuntu)上,此命令称为rename.ul。如果.txt除了最终扩展名以外没有其他出现,则可以写

    rename .txt .bak *.txt
    
  • rename是Debian及其衍生产品附带的Perl脚本/usr/bin/rename。您可以根据任意Perl命令重命名文件。

    rename 's/\.txt\z/\.bak/' *.txt
    
  • mmv,它可以根据几种基于名称的模式来重命名,复制和链接文件,并且具有许多与目标名称已经存在时发生的情况有关的选项。请注意,必须使用引号来防止通配符被外壳扩展。

    mmv '*.txt' '#1.txt'
    
  • zmvzsh函数,仅当外壳为zsh时才可用。它可以匹配任意的zsh模式(因此,您可以根据任意的正则表达式匹配文件名,而不仅仅是通配符,还可以通过其他条件(例如日期和大小)来匹配文件)。zmv也可以复制和链接。

    zmv '(*).txt' '$1.txt'
    

如果您对使用的计算机有一定的控制权,我的建议是使用zsh作为外壳程序(与bash相比有其他好处),并将这些行放在您的计算机中~/.zshrc

autoload -U zmv
alias zmv='noglob zmv -w'
alias zcp='zmv -C'
alias zln='zmv -L'
alias zsy='zmv -Ls'

noglob是zsh的一项功能,它告诉外壳程序不要在命令的参数中扩展通配符。这样您就可以写zmv *.txt \$1.txt(您始终需要$在替换文本中保护)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.