【问题标题】:How to remove filename prefix with a Posix shell如何使用 Posix shell 删除文件名前缀
【发布时间】:2012-05-19 03:25:31
【问题描述】:

如何删除 Bash 中的文件名前缀,如下例所示:

XY TD-11212239.pdf

得到

11212239.pdf

即删除XY TD-?

【问题讨论】:

  • Linux 是一个内核。您实际上是指 [bash] 或 [sh](或其他 shell)吗?
  • @Shahbaz 的编辑:虽然 OP 可能意味着“shell”,但实际上甚至可以通过编写 C 程序来完成,例如。我的意思是:最好让 OP 澄清他是否指的是“外壳”。
  • @ArjunShankar,我从标题中删除了 shell,但顺便说一下他正在执行命令 (XY file-name),我仍然相信他想在 shell 中执行此操作。
  • @Shahbaz:嗯.. 但是 OP 说 XY TD- 是“文件名前缀”,他想删除它。那么'XY'可能不是shell命令。
  • @hamid - 你想重命名文件删除前缀吗?您想在 shell 中(如 bash)还是在程序中(哪种语言?)?

标签: bash shell prefix


【解决方案1】:

您说过 POSIX shell,其中包括 BASH、Kornshell、Ash、Zsh 和 Dash。幸运的是,所有这些 shell 都对变量值进行模式过滤

当您在 Unix/Linux 命令行上指定带有 * 之类的文件时,您会使用模式:

$ ls *.sh  # Lists all files with a `.sh` suffix

这些 POSIX shell 使用四种不同的模式过滤:

  • ${var#pattern} - 从左侧删除与模式匹配的最小字符串。
  • ${var##pattern} - 从左侧删除与模式匹配的最大字符串。
  • ${var%pattern} - 从右侧删除与模式匹配的最小字符串。
  • ${var%%pattern} - 从右侧删除与模式匹配的最大字符串。

这里有几个例子:

foo="foo-bar-foobar"
echo ${foo#*-}   # echoes 'bar-foobar'  (Removes 'foo-' because that matches '*-')
echo ${foo##*-}  # echoes 'foobar' (Removes 'foo-bar-')
echo ${foo%-*}   # echoes 'foo-bar'
echo ${foo%%-*}  # echoes 'foo'

您没有真正解释您想要什么,也没有包含任何代码示例,因此很难想出可以满足您需求的东西。但是,使用模式过滤,您可能可以准确地确定要对文件名做什么。

file_name="XY TD-11212239.pdf"
mv "$file_name" "${file_name#*-}" # Removes everything from up to the first dash

【讨论】:

    【解决方案2】:

    您提供的信息很少,但假设您在 bash 中执行此操作,并且有一个需要删除前缀的文件列表,您可以通过 sed 管道列表:

    例如:

    ./generate_your_list_of_files | sed -e 's/^prefix//'
    

    或者如果您的文件列表是空格分隔的:

    echo TD-file1 TD-file2.x.yt TD-file3-beep | sed -e 's/\<TD-//g'
    

    第一个匹配行首的前缀并将其删除。第二个匹配TD-(或任何其他您想要替换的前缀)仅当它出现在单词的开头并在所有行的所有匹配中替换它时。这可能会变得很危险,例如像TD-file\ that\ TD-contains\ space.txt 这样的文件会变成file\ that\ contains\ space.txt

    附带说明,不要使用ls 获取文件列表。 That's a horrible mistake。如果您需要获取要使用的文件列表并在多个地方引用,我建议将它们放在一个数组中:

    files=(*)
    

    然后使用这个数组。


    由于受欢迎的要求(下面的单个评论),这里是如何重命名目录中以XY TD- 开头的所有文件,以便删除前缀(感谢@tripleee):

    for file in prefix*;
    do
        mv "$file" "${file#XY TD-}"
    done
    

    【讨论】:

    • OP 也可能想要“重命名”原始文件。这些问题实在是太模糊了,无法充分回答。
    • @tripleee,感谢您告诉我。我实际上只是最近才学习 bash 的脚本语言。我已经更新了我的答案。
    • ... 为了效率和正确性,mv "$file" "${file#XY\ TD-}" 带有正确的引用和 shell 的内置替换机制。
    • @tripleee,也感谢您提供的精彩链接。作为 shell 编程的新手,老实说,我会为那些无用的用法而堕落。
    • 用于“PM ID-”中的文件*;做 mv $file echo $file | sed -e 's/^PM ID-//';完成 // 此代码无法从文件名中删除前缀 PM ID-
    【解决方案3】:

    您也可以使用重命名工具

    用自制软件安装

    brew install rename

    然后从目录中运行以下命令,从所有文件中删除“前缀-”

    rename -d prefix- *

    【讨论】:

    • 好强大的perl 工具!
    【解决方案4】:

    除了其他答案中显示的子字符串提取之外,您还可以使用子字符串替换。给定文件:

    fn="XY TD-11212239.pdf"
    

    然后子串替换:

    fn_new=${fn//*TD-/}
    

    也会做你想做的。

    【讨论】:

    • 今天这救了我的理智。谢谢。
    【解决方案5】:
    $ s='XY TD-11212239.pdf'
    $ echo "${s#XY TD-}"
    11212239.pdf
    

    如果您的目标是执行批量重命名:

    while IFS= read -r -d '' filename; do
      mv "$filename" "${filename#XY TD-}"
    done < <(find . -type f -name 'XY TD-*' -print0)
    

    请注意,&lt;() 是 POSIX sh 中不存在的 bash 扩展。您可以将其替换为find ... | while 形式的管道。

    同样,-print0 是 POSIX 查找中不存在的 GNU 扩展。 POSIX find 没有提供对包含换行符的名称安全的文件定位方法,因此很难替换。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-08-15
      • 2018-12-22
      • 1970-01-01
      • 2011-03-25
      • 2016-12-27
      • 2017-07-08
      • 1970-01-01
      相关资源
      最近更新 更多