重命名文件以添加后缀


13

我需要一个命令来重命名当前工作目录中的所有文件,以使新文件名与旧文件名相同,但包括与原始文件的行数相对应的后缀(例如,如果文件f有10个行,则应将其重命名为f_10)。

这是我的(无效)尝试:

 linenum=$(wc -l); find * -type f | grep -v sh | rename 's/^/ec/'*

您可以做出答案!(如果它为现有的答案添加了新的内容-但看起来确实如此)
Volker Siegel 2015年

Answers:


13

怎么样:

for f in *; do mv "$f" "$f"_$(wc -l < "$f"); done

例如:

$ wc -l *
 10 file1
 40 file2
100 file3
$ ls
file1_10  file2_40  file3_100

如果您想保留扩展名(如果有),请改用以下方法:

for f in *; do 
    ext=""; 
    [[ $f =~ \. ]] && ext="."${f#*.}; 
    mv "$f" "${f%%.*}"_$(wc -l < "$f")$ext; 
done

谢谢terdon!此命令行似乎可以完成工作,但是如何将点(。)更改为(_)?另外,由于我的脚本位于文件夹中,因此它也被重命名,因此允许我的脚本执行一次(因为脚本名称已更改...)
Martin Yeboah 2015年

@MartinYeboah看到更新的答案_。至于剧本,什么剧本?那应该从命令行运行,不需要脚本。如果只希望它与某些文件匹配,则将更改in *为例如in *txt
terdon

非常感谢;)我完全忘记了它应该从命令行执行:)
Martin Yeboah 2015年

我认为wc -l < $f代替grep会更容易理解(也许执行起来更好,但我没有检查过)。
musiKk 2015年

@musiKk是的,但是由于其他答案正在使用wc,我想展示一种不同的方法。但是,还可以。
terdon

10

您可以尝试以下一种衬垫:

find . -maxdepth 1 -type f -exec bash -c 'mv -i "$1" "$1.$(wc -l <"$1")"' _ {} \;
  • 这将在当前工作目录(find . -maxdepth 1 -type f)中找到所有文件

  • 然后,我们在找到的文件上运行shell实例,以重命名文件以追加行数。

范例:

$ ls
bar.txt spam.txt foo.txt

$ find . -maxdepth 1 -type f -exec bash -c 'mv -i "$1" "$1.$(wc -l <"$1")"' _ {} \;

$ ls
bar.txt.12 foo.txt.24 spam.txt.7

6

保留扩展名(如果存在)的另一种方法是rename

for f in *; do rename -n "s/([^.]+)(\.?.*)/\$1_$(< "$f" wc -l)\$2/" "$f"; done

如果结果是预期的,请删除该-n选项:

for f in *; do rename "s/([^.]+)(\.?.*)/\$1_$(< "$f" wc -l)\$2/" "$f"; done

rename伟大=)+1
AB

1
这在abcd上不会失败吗?将第二个捕获组更改为(\.?[^\.]+)
ps95

@ prakharsingh95是的,但是(\.?[^\.]+)也不行,因为它只能匹配第二个点,并且不匹配具有连续点或以点结尾的文件名。这不是一个容易解决的难题,唯一的方法似乎是进行两次替换。
kos

@kos你是正确的。怎么样([^ \。] +)。*?([^ \。] + $)我不确定最优性。工作提琴:regex101.com/r/rQ9lX1/1
ps95

1
@ prakharsingh95您不想.在字符类中转义。
terdon

5

使用find

find . -maxdepth 1 -type f -print0 | while read -d $'\0' f; do mv "$f" "$f"_$(grep -c . "$f"); done

% wc -l *
  3 doit
  5 foo

% find . -maxdepth 1 -type f -print0 | while read -d $'\0' f; do mv "$f" "$f"_$(grep -c . "$f"); done

% wc -l *                         
  3 doit_3
  5 foo_5

为什么-name "*"呢?剩下的测试?;)
kos 2015年

1
@kos旧习惯:\
AB

3

只是为了好玩,并咯咯地笑了一个解决方案rename。由于rename是Perl工具,可以接受评估的任意字符串,因此您可以进行各种欺骗。似乎可行的解决方案如下:

rename 's/.*/open(my $f, "<", $_);my $c=()=<$f>;$_."_".$c/e' *

有趣的主意+1
AB

2

该脚本包含以下几种情况:单点和扩展名(file.txt),多个点和扩展名(file.1.txt),连续点(file..foobar.txt)和文件名中的点(file。或文件..)。

剧本

#!/bin/bash
# Author: Serg Kolo
# Date:  June 25,2015
# Description: script to rename files to file_numlines
# written for http://askubuntu.com/q/640430/295286

# Where are the files ?
WORKINGDIR=/home/xieerqi/substitutions
# Where do you want them to go ?
OUTPUTDIR=/home/xieerqi/substitutions/output

for file in $WORKINGDIR/* ;do 
    FLAG=0
    EXT=$(printf "%s" "$file" | awk -F'.' '{printf "%s",$NF }' )  # extension, last field of dot-separated string
    # EXT="${file##*.}" # Helio's advice is to use parameter expansion, but I dont know how to use it
    if [ -z $EXT ]; then # we have a dot at the end case file. or something
        # so we gotta change extension and filename
        EXT=""
        FILENAME=$(printf "%s" "$file" | awk -F '/' '{ print $NF}' )
        # set flag for deciding how to rename
        FLAG=1
    else
        FILENAME=$( printf "%s" "$file" | awk -F '/' -v var=$EXT '{gsub("."var,"");print $NF}'   ) # filename, without path, lst in
    fi

    NUMLINES=$(wc -l "$file" | awk '{print $1}') # line count

    if [ $FLAG -eq 0 ];then
         echo "$file" renamed as "$OUTPUTDIR"/"$FILENAME"_"$NUMLINES"."$EXT"
        # cp "$file" "$OUTPUTDIR"/"$FILENAME"_"$NUMLINES"."$EXT" # uncomment when necessary
    else
        echo "$file" renamed as "$OUTPUTDIR"/"$FILENAME"_"$NUMLINES""$EXT"
        # cp "$file" "$OUTPUTDIR"/"$FILENAME"_"$NUMLINES""$EXT" # uncomment when necessary
    fi

    #printf "\n"

done

剧本在行动

$./renamer.sh                                                                                                           
/home/xieerqi/substitutions/file. renamed as /home/xieerqi/substitutions/output/file._0
/home/xieerqi/substitutions/file.. renamed as /home/xieerqi/substitutions/output/file.._0
/home/xieerqi/substitutions/file.1.jpg renamed as /home/xieerqi/substitutions/output/file.1_3.jpg
/home/xieerqi/substitutions/file.1.test.jpg renamed as /home/xieerqi/substitutions/output/file.1.test_3.jpg
/home/xieerqi/substitutions/file.1.test.txt renamed as /home/xieerqi/substitutions/output/file.1.test_2.txt
/home/xieerqi/substitutions/file.1.txt renamed as /home/xieerqi/substitutions/output/file.1_2.txt
/home/xieerqi/substitutions/file.2.jpg renamed as /home/xieerqi/substitutions/output/file.2_3.jpg
/home/xieerqi/substitutions/file.2.test.jpg renamed as /home/xieerqi/substitutions/output/file.2.test_3.jpg
/home/xieerqi/substitutions/file.2.test.txt renamed as /home/xieerqi/substitutions/output/file.2.test_2.txt
/home/xieerqi/substitutions/file.2.txt renamed as /home/xieerqi/substitutions/output/file.2_2.txt
/home/xieerqi/substitutions/foo..bar.txt renamed as /home/xieerqi/substitutions/output/foo..bar_4.txt

请注意,文件中没有行。和file ..,因此行数为0

特别感谢Terdon和Helio审核了脚本并提出了建议的修改


2

@helio在聊天中开发的另一种bash方式:

for file in *
do
    echo "$file"
    [[ -f "$file" ]] || continue
    [[ $file =~ (.*)(\.[^.]+)$ ]]
    cp "$file" "output/${BASH_REMATCH[1]:-$file}_$(wc -l < "$file")${BASH_REMATCH[2]}"
done

怪异的单头家伙,头顶发育不良((.*)(\.[^.]+)$)应该只匹配适当的扩展名(.foo,而不是..)。如果没有扩展名,则该BASH_REMATCH数组将为空。我们可以通过使用filename的默认值${BASH_REMATCH[1]:-$file}并按原样使用扩展名来利用这一点。

要处理点文件,可以find按照terdon和Helio的建议使用。

find -maxdepth 1 -type f -printf '%P\0' | 
while IFS= read -r -d '' file
do
    [[ $file =~ (.*)(\.[^.]+)$ ]]
    cp "$file" "output/${BASH_REMATCH[1]:-$file}_$(wc -l < "$file")${BASH_REMATCH[2]}"
done

+1:我将无法对该命令进行解释。;-)
Helio 2015年
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.