Đổi tên tập tin để thêm hậu tố


13

Tôi cần một lệnh để đổi tên tất cả các tệp trong thư mục làm việc hiện tại, theo cách mà tên tệp mới sẽ giống như cũ, nhưng bao gồm một hậu tố tương ứng với số dòng của các tệp gốc (ví dụ: nếu tệp fcó 10 dòng sau đó nên được đổi tên thành f_10).

Đây là nỗ lực (không hoạt động) của tôi:

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

Bạn có thể làm cho nó một câu trả lời! (Nếu nó thêm một cái gì đó mới vào các câu trả lời hiện có - nhưng có vẻ như vậy)
Volker Siegel

Câu trả lời:


13

Làm thế nào về:

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

Ví dụ:

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

Nếu bạn muốn giữ các tiện ích mở rộng (nếu có), hãy sử dụng tiện ích này thay thế:

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

Cảm ơn terdon! dòng lệnh này dường như hoàn thành công việc nhưng làm cách nào tôi có thể thay đổi dấu chấm (.) thành (_)? Ngoài ra, vì tập lệnh của tôi nằm trong thư mục, nó cũng được đổi tên và do đó cho phép tập lệnh của tôi được thực thi một lần (vì tên tập lệnh thay đổi ...)
Martin Yeboah

@MartinYeboah xem câu trả lời cập nhật cho _. Còn về kịch bản, kịch bản nào? Điều đó nên được chạy từ dòng lệnh, không cần kịch bản. Nếu bạn chỉ muốn nó khớp với một số tệp, in *ví dụ, thay đổi thành , in *txthoặc một cái gì đó.
terdon

cảm ơn rất nhiều;) Tôi hoàn toàn quên rằng nó nên được thực thi từ dòng lệnh :)
Martin Yeboah

Tôi nghĩ wc -l < $fthay vì grep sẽ dễ hiểu hơn (và có thể tốt hơn để thực hiện nhưng tôi đã không kiểm tra điều đó).
musiKk

@musiKk có, nhưng vì các câu trả lời khác đang sử dụng wc, tôi muốn thể hiện một cách tiếp cận khác. Nhưng OK, đủ công bằng.
terdon

10

Bạn có thể thử một lót này:

find . -maxdepth 1 -type f -exec bash -c 'mv -i "$1" "$1.$(wc -l <"$1")"' _ {} \;
  • Điều này sẽ tìm thấy tất cả các tệp trong thư mục làm việc hiện tại ( find . -maxdepth 1 -type f)

  • Sau đó, chúng tôi đang chạy một phiên bản shell trên các tệp được tìm thấy để đổi tên các tệp để nối thêm số lượng dòng.

Thí dụ :

$ 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

Một cách khác để bảo tồn phần mở rộng (nếu có) bằng cách sử dụng rename:

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

Nếu kết quả là kết quả mong đợi, hãy xóa -ntùy chọn:

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

renametuyệt vời =) +1
AB

1
Điều này sẽ không thất bại trên abcd? Thay đổi nhóm chụp thứ hai thành(\.?[^\.]+) .
ps95

@ prakharsingh95 Điều đó đúng, tuy nhiên (\.?[^\.]+)cũng không ổn vì nó sẽ chỉ khớp với dấu chấm thứ hai và sẽ không khớp với tên tệp có dấu chấm liên tiếp hoặc kết thúc bằng dấu chấm bất kể. Đó không phải là một giải pháp dễ dàng khó khăn, cách duy nhất dường như thực hiện hai sự thay thế.
kos

@kos bạn đúng rồi. Còn về ([^ \.] +). *? ([^ \.] + $) Tôi không chắc về sự tối ưu. Fiddle
ps95

1
@ prakharsingh95 bạn không muốn trốn thoát .trong các lớp nhân vật.
terdon

5

Sử dụng find:

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

Thí dụ

% 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

Tại sao -name "*"? Còn lại từ các bài kiểm tra? ;)
kos

1
@kos Thói quen cũ: \
AB

3

Chỉ để cho vui và cười khúc khích với một giải pháp với rename. Vì renamelà một công cụ Perl chấp nhận một chuỗi tùy ý là eval'd, bạn có thể thực hiện tất cả các loại shenanigans. Một giải pháp có vẻ hiệu quả như sau:

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

Ý tưởng thú vị +1
AB

2

Kịch bản dưới đây bao gồm nhiều trường hợp: dấu chấm đơn và phần mở rộng (file.txt), nhiều dấu chấm và phần mở rộng (file.1.txt), dấu chấm liên tiếp (file..foobar.txt) và dấu chấm trong tên tệp (tệp. Hoặc tập tin..).

Kịch bản

#!/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

Kịch bản hành động

$./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

Lưu ý rằng không có dòng trong tập tin. và tệp .., do đó số dòng là 0

Đặc biệt cảm ơn terdon và Helio đã xem xét kịch bản và đề xuất chỉnh sửa


2

Một cách bash khác, được phát triển với @Helio trong trò chuyện :

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

Anh chàng có vẻ ngoài đơn điệu kỳ lạ với cái đầu thứ hai còi cọc ( (.*)(\.[^.]+)$) chỉ nên phù hợp với các phần mở rộng thích hợp ( .foo, không ..). Nếu không có phần mở rộng, thì BASH_REMATCHmảng sẽ trống. Chúng ta có thể tận dụng điều này bằng cách sử dụng giá trị mặc định cho tên tệp${BASH_REMATCH[1]:-$file} và chỉ sử dụng phần mở rộng.

Để xử lý các tệp chấm, bạn có thể sử dụng find, như được đề xuất bởi terdon và 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: Tôi sẽ không thể giải thích cho lệnh. ;-)
Helio
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.