处理带有特殊首字符的文件名(例如?)

Zir*_*ode 29 command-line special-characters filenames fish wildcards

我最近遇到了一个名称以字符“?”开头的文件。我想复制这个文件,将它输入ffmpeg,并在终端中以各种其他方式引用它。我通常会自动完成奇怪的文件名,但这会失败,因为我什至无法输入第一个字母。

我不想切换到鼠标来执行复制粘贴操作。我不想为可能的场景记住一堆代码。我的临时解决方案是切换到vim,粘贴!ls并复制有问题的字符,然后退出并将其粘贴到终端中。这有效,但非常可怕。

有没有更简单的方法来处理这种情况?

注意:如果鱼壳发生变化,我将使用它。

jim*_*mij 34

如果文件名的第一个字符可打印但既不是字母数字也不是空格,则可以使用[[:punct:]]glob 运算符:

$ ls *.txt
f1.txt  f2.txt  ?abc.txt
$ ls [[:punct:]]*.txt
?abc.txt
Run Code Online (Sandbox Code Playgroud)


小智 6

我想到的最简单的方法是ls [^a-zA-Z0-9]*它对我有用,但 terdon 的回答更好地引起人们对 extglob shell 选项甚至独立于 shell 的方法的关注。


Mat*_*upt 6

ls 有一些开关(如--quote-name、--escape、--literal)用于处理不可打印的字符,但在这种情况下,该字符似乎是“可打印的”而不是“可键入的”(至少在我的键盘上! ),所以这些开关似乎都没有帮助。

因此,作为删除名称中包含任何字符的文件的一般“蛮力”方法,您可以这样做:

$ /bin/ls -1A|cat -n  # list all files (except . and ..), 1 per line, add line numbers
     1  ?
     2  f1.txt
     3  f2.txt
Run Code Online (Sandbox Code Playgroud)

找到包含违规文件的行。很可能它是第一行,但假设它是第五行。打印第 5 行并对其进行十六进制编码:

$ /bin/ls -1A|sed -n 5p|xxd -g 1
0000000: e2 99 ab 0a                                      ....
Run Code Online (Sandbox Code Playgroud)

忽略 0a(换行符)字符,构造一个转义字符串,并使用 echo 的 -e 选项来翻译转义:

$ echo -e '\xe2\x99\xab'
?
Run Code Online (Sandbox Code Playgroud)

现在您可以像这样复制/移动/删除它:

$ cp -vi $(echo -e '\xe2\x99\xab') better_name
‘?’ -> ‘better_name’
Run Code Online (Sandbox Code Playgroud)

此外,如果您不限于使用 shell 脚本,您可以在 Python 中这样做:

$ python
>>> import os
>>> os.listdir('.')
[ ..., '\xe2\x99\xab', ... ]
>>> print '\xe2\x99\xab'
?
>>> import shutil
>>> shutil.copy('\xe2\x99\xab', 'better_name')
Run Code Online (Sandbox Code Playgroud)

使用这种方法,您可以处理许多文件,您只需编写选择正确文件的逻辑,并在不破坏的情况下重命名它们等:

for f in os.listdir('.'):
  if not f.isalnum():
    newname = generate_newname(f)
    if not os.path.exists(newname):
      shutil.copy(f, newname)
    else:
      print newname, 'already exists!'
Run Code Online (Sandbox Code Playgroud)


ter*_*don 5

类似的方法是列出所有不以“正常”字符开头的文件。在 bash 中,您可以使用

$ shopt -s extglob
$ ls !([[:alpha:]]*)
Run Code Online (Sandbox Code Playgroud)

但是,这似乎不适用于fish,因此您可以find改用:

$ find . -type f -not -name '[[:alpha:]]*'
Run Code Online (Sandbox Code Playgroud)


Vol*_*gel 5

重命名符号链接

\n\n

处理带有特殊字符(作为第一个字符或文件名中其他位置)的文件名的一种方法是重命名为更简单的名称

\n\n

即使您需要保留原始文件名,也可以使用此功能:重命名文件名的副本。
\n这可以通过复制文件来完成,也可以通过创建文件的符号链接或硬链接并重命名它们来完成。cp使用选项-s-l对于硬链接)创建符号链接而不是副本。

\n\n

用“排毒”来净化名字

\n\n

为了重命名为干净的文件名,detox可以使用;它根据detoxrc文件中定义的各种规则重命名文件以清理文件名。默认情况下,UTF8 字符会被删除;使用选项,-s utf_8-only它们被替换为_

\n\n
$ touch \'\xe2\x99\xab \xe6\xbc\xa2\xe5\xad\x97\xe3\x82\xab\' \xe2\x99\xabfoo\n$ ls -1\n\xe2\x99\xabfoo\n\xe2\x99\xab \xe6\xbc\xa2\xe5\xad\x97\xe3\x82\xab\n$ detox -s utf_8-only * \n$ ls -1                \n_ ___\n_foo\n
Run Code Online (Sandbox Code Playgroud)\n\n


\n\n

符号链接上的“排毒”

\n\n

结合上述符号链接的处理:

\n\n
$ mkdir orig\n$ cd orig \n$ touch \'\xe2\x99\xab \xe6\xbc\xa2\xe5\xad\x97\xe3\x82\xab\' \xe2\x99\xabfoo\n$ cd ..\n$ mkdir clean\n$ cd clean \n$ cp -s ../orig/* .\n$ ll               \nlrwxrwxrwx 1 14 Oct  8 05:52 \xe2\x99\xabfoo -> ../orig/\xe2\x99\xabfoo\nlrwxrwxrwx 1 21 Oct  8 05:52 \xe2\x99\xab\\ \xe6\xbc\xa2\xe5\xad\x97\xe3\x82\xab -> ../orig/\xe2\x99\xab\\ \xe6\xbc\xa2\xe5\xad\x97\xe3\x82\xab\n$ ls -1\n\xe2\x99\xabfoo\n\xe2\x99\xab \xe6\xbc\xa2\xe5\xad\x97\xe3\x82\xab\n$ detox --special -s utf_8-only *\n$ ll                                \nlrwxrwxrwx 1 21 Oct  8 05:52 _\\ ___ -> ../orig/\xe2\x99\xab\\ \xe6\xbc\xa2\xe5\xad\x97\xe3\x82\xab\nlrwxrwxrwx 1 14 Oct  8 05:52 _foo -> ../orig/\xe2\x99\xabfoo\n
Run Code Online (Sandbox Code Playgroud)\n