LinuxBash-如何删除文件夹中包含的文件名的一部分

LinuxBash-如何删除文件夹中包含的文件名的一部分,bash,replace,sed,find,Bash,Replace,Sed,Find,我有几个目录,其中包含一些文件,这些文件的名称包含文件夹的名称,或者更多其他单词。 例如: 我愿意继续这样做: one/berg.txt two/tree.txt three/water.txt 我尝试使用sed命令、find命令、for命令等。 我必须想办法得到它 你能帮我吗?。谢谢你这里有一种方法可以在sed的帮助下完成: #!/bin/bash find -type f -print0 | \ while IFS= read -r -d '' old_path; do

我有几个目录,其中包含一些文件,这些文件的名称包含文件夹的名称,或者更多其他单词。 例如:

我愿意继续这样做:

one/berg.txt
two/tree.txt
three/water.txt
我尝试使用sed命令、find命令、for命令等。 我必须想办法得到它


你能帮我吗?。谢谢你

这里有一种方法可以在sed的帮助下完成:

#!/bin/bash

find -type f -print0 | \
    while IFS= read -r -d '' old_path; do
        new_path="$(echo "$old_path" | sed -e 's|/\([^/]\+\)/\([^/]\+\) - \1.\([^/.]\+\)$|/\1/\2.\3|')"
        if [[ $new_path != $old_path ]]; then
            echo mv -- "$old_path" "$new_path"
          # ^^^^ remove this "echo" to actually rename the files
        fi
    done
您必须
cd
到包含所有这些文件的顶级目录才能执行此操作。此外,它还包含一个
echo
,因此它实际上不会重命名文件。运行它一次,看看您是否喜欢它的输出,如果喜欢,请删除
echo
,然后再次运行它


基本思想是,我们迭代所有文件,对于每个文件,我们试图找到文件是否与给定模式匹配。如果是,我们将其重命名。该模式检测(并捕获)路径的第二个最后一个组件,并将路径的最后一个组件分为3部分:前缀、后缀(必须与前一个路径组件匹配)和扩展名。

简短而简单,如果您有GNU find:

find . -name '* - *.*' -execdir bash -c '
  for file; do
    ext=${file##*.}
    mv -- "$file" "${file%% - *}.${ext}"
  done
' _ {} +

  • -execdir
    在找到每组文件的目录中执行给定的命令,因此不必担心目录名
  • 用于文件;do
    是在“$@”中为文件编写
    的较短方法;执行
  • ${file###*.}
    扩展到
    $file
    的内容,删除最后一个
    之前的所有内容(因此,它扩展到文件的扩展名)
  • “${varname%%-*}”
    扩展到变量
    varname
    的内容,并从末尾删除
    之后的所有内容
  • 在习惯用法
    -exec bash-c'.'{}+
    (与
    -execdir
    一样)中,传递给
    bash-c
    的脚本以
    \ucode>作为
    $0
    运行,
    找到的所有文件在后续位置查找

文件路径真的是
one/berg-one.txt
,还是
one/berg-one.txt
?您的问题,并使用
{}
按钮使示例易读。Sí、./uno/filename-uno.txt-我想删除文件名中的目录名。是否要删除
-
和扩展名之间的所有内容?或者仅当它与目录名相同时?@PacoRodriguez目录名是否真的包含前导空格和尾随空格?所有的文件名都是以前导空格开头的吗?顺便说一句,我对这种方法最大的不满是,它在包含换行文字的文件名上表现得很糟糕——虽然POSIX不需要换行文字,但常见的UNIX文件系统在实践中确实允许这样做。如果要从
查找
,最好使用
-print0
,相应地,
IFS=read-r-d''old_path
。El functionamiento del script es correction。埃索时代的布斯卡巴。谢谢你。(“最大的”--另一种是在循环中调用
sed
,这是一种实践,使shell以其速度慢而赢得了它应得的声誉;不管怎样,我们都会使用fork+exec开销来调用
mv
,但这意味着额外的fork来生成运行
sed
的子shell,另一个
exec
,一个FIFO正在设置中然后从中读取以读取子流程的输出,等等)。@CharlesDuffy您在这两个方面都是对的。我通过更新我的答案解决了您的第一个问题(我总是懒得这样做,因为我总是忘记
-d'
关于
阅读的事情)。至于第二个,在本例中,我喜欢
sed
中的regex如何为重命名文件名提供更强的保证,这就是为什么我更喜欢使用纯bash解决方案。我还喜欢这个解决方案在
Θ(1)
内存中运行。关于“保证重命名文件”——这就是为什么我的答案中的glob只匹配保证同时包含
模式的文件,然后是一个点——这两个点都保证后面的PE依赖。不过,您是对的,如果对通过参数扩展传递的输入所涉及的保证不加注意,很容易就不会发生替换。
find . -name '* - *.*' -execdir bash -c '
  for file; do
    ext=${file##*.}
    mv -- "$file" "${file%% - *}.${ext}"
  done
' _ {} +