2010-09-08 42 views
45

Tôi có một thư mục với khoảng 1.700 tệp. Chúng được đặt tên là 1.txt hoặc 1497.txt, v.v. Tôi muốn đổi tên tất cả các tệp sao cho tất cả tên tệp dài bốn chữ số.Tập lệnh shell Linux để thêm số 0 đứng đầu vào tên tệp

I.e., 23.txt trở thành 0023.txt.

Kịch bản lệnh shell sẽ thực hiện điều này là gì? Hoặc câu hỏi liên quan: Làm cách nào để sử dụng grep để chỉ khớp các dòng có chứa \d.txt (tức là, một chữ số, sau đó một dấu chấm, sau đó là các chữ cái txt)?

Dưới đây là những gì tôi có cho đến nay:

for a in [command i need help with] 
do 
    mv $a 000$a 
done 

Về cơ bản, chạy mà ba lần, với các lệnh đó để tìm một chữ số, hai chữ số, và ba tên tập tin chữ số (với số lượng các zeros ban đầu đã thay đổi).

+1

Bạn nên thẻ này với vỏ bạn đang sử dụng – meagar

+0

trùng lặp có thể xảy ra của [Bash script để đệm các tên tập tin] (http://stackoverflow.com/questions/55754/bash-script-to-pad-file-names) –

+1

@CiroSantilli, tình cờ, tôi đã có ai đó gần đây đẩy lùi về một dupe bị đóng cửa với điều đó logic cho các số pad đầu và logic đến các số pad sau này trong một tên khác một chút. (Do đó, https://stackoverflow.com/questions/46993470/padding-filenames-with-zeros-in-bash hiện đã gắn cờ một câu trả lời của câu trả lời này và * không * một phần của câu trả lời đó). –

Trả lời

46

Hãy thử:

for a in [0-9]*.txt; do 
    mv $a `printf %04d.%s ${a%.*} ${a##*.}` 
done 

Thay đổi mô hình tên file ([0-9]*.txt) khi cần thiết.


Một mục đích chung được liệt kê đổi tên mà làm cho không có giả định về thiết lập ban đầu của tên tập tin:

X=1; 
for i in *.txt; do 
    mv $i $(printf %04d.%s ${X%.*} ${i##*.}) 
    let X="$X+1" 
done 

Trên cùng một chủ đề:

+0

Điều này xuất ra một loạt lỗi cho mỗi tên tệp đã có 4 chữ số. Thêm foo vào lúc bắt đầu sẽ nhận được xung quanh này, nhưng tôi không muốn điều đó. Cảm ơn những liên kết đó. –

+0

Xin lỗi vì "foo" ... Sao chép/dán sai –

0

Để chỉ phù hợp với các file văn bản chữ số duy nhất, bạn có thể làm ...

$ ls | grep '[0-9]\.txt' 
+0

Có cách nào để xóa '.txt' khỏi $ a không? Tôi đã tự hỏi điều này nhiều lần trước đây. –

+0

Có, '$ {a% .txt}' sẽ làm điều đó (hoặc '$ {a%. *}' Để loại bỏ bất kỳ hậu tố nào). –

+0

Một cách nhanh chóng nếu bạn biết phần mở rộng trước đây là đường ống đầu ra thông qua sed, như thế này: 'ls | grep '[0-9] \. txt' | sed 's/\. txt // g'' – LukeN

11
for a in *.txt; do 
    b=$(printf %04d.txt ${a%.txt}) 
    if [ $a != $b ]; then 
    mv $a $b 
    fi 
done 
+0

Cảm ơn bạn đã trả lời! Về cơ bản giống như một trong những khác đến trong cùng một lúc chính xác. –

+1

@David: Giải pháp của tôi không gây ra một loạt lỗi. :-P –

+0

Không gây ra lỗi ** nếu ** tên tệp đầu vào không có dấu cách. Có lẽ nên thêm nhiều dấu ngoặc kép để tránh điều đó. :) –

7

One-liner:

ls | awk '/^([0-9]+)\.txt$/ { printf("%s %04d.txt\n", $0, $1) }' | xargs -n2 mv 

Làm thế nào để sử dụng grep để dòng trận đấu duy nhất mà chứa \ d.txt (IE 1 chữ số, sau đó một thời gian, sau đó các chữ txt)?

grep -E '^[0-9]\.txt$' 
12

Sử dụng kịch bản rename (prename trong một số trường hợp) mà đôi khi được cài đặt với Perl, bạn có thể sử dụng biểu thức Perl để làm việc đổi tên. Kịch bản bỏ qua đổi tên nếu có xung đột tên.

Lệnh dưới đây chỉ đổi tên các tệp có bốn chữ số trở xuống, sau đó là phần mở rộng ".txt". Nó không đổi tên các tập tin mà không hoàn toàn phù hợp với mô hình đó. Nó không cắt ngắn tên bao gồm nhiều hơn bốn chữ số.

rename 'unless (/0+[0-9]{4}.txt/) {s/^([0-9]{1,3}\.txt)$/000$1/g;s/0*([0-9]{4}\..*)/$1/}' * 

Một vài ví dụ:

Original Becomes 
1.txt  0001.txt 
02.txt  0002.txt 
123.txt  0123.txt 
00000.txt 00000.txt 
1.23.txt 1.23.txt 

câu trả lời khác cho đến nay sẽ cố gắng để đổi tên file mà không phù hợp với các mô hình, sản xuất lỗi cho tên tệp chứa ký tự không phải chữ số, thực hiện đặt lại tên tạo ra xung đột tên, hãy thử và không đổi tên các tệp có không gian trong tên của họ và có thể là các sự cố khác.

+0

Yagni. Nghiêm túc. Ai quan tâm đến tên tệp có chứa dấu cách hoặc ký tự không phải chữ số nếu không nằm trong phạm vi của câu hỏi? Nếu OP muốn viết một kịch bản sử dụng chung, anh ta đã nói như vậy trong câu hỏi, và câu trả lời sẽ có chỗ cho phù hợp. –

+13

@ Chris: Câu trả lời của tôi thường làm hai việc. Một, họ cố gắng trả lời câu hỏi của OP.Hai, họ cố gắng cung cấp thêm thông tin có thể hữu ích cho người xem trong tương lai của câu hỏi. –

+2

@ Dennis: Cảm ơn bạn đã cung cấp câu trả lời này, câu trả lời được đánh giá hàng đầu không giải quyết được vấn đề cụ thể của tôi nhưng như bạn đã lưu ý, bạn đã cung cấp câu trả lời tổng quát hơn và rộng hơn hơn. Cảm ơn. –

4

Giả sử bạn có tệp với datatype .dat trong thư mục của mình. Chỉ cần sao chép mã này vào một file có tên run.sh, làm cho nó thực thi bằng cách chạy chmode +x run.sh và sau đó thực hiện sử dụng ./run.sh:

#!/bin/bash 
num=0 
for i in *.dat 
do 

    a=`printf "%05d" $num` 
    mv "$i" "filename_$a.dat" 
    let "num = $(($num + 1))" 
done 

này sẽ chuyển đổi tất cả các file trong thư mục của bạn để filename_00000.dat, filename_00001.dat vv

0

Đề xuất một lớp:

while [ -f ./result/result`printf "%03d" $a`.txt ]; do a=$((a+1));done 
RESULT=result/result`printf "%03d" $a`.txt 
1

Phiên bản này cũng hỗ trợ xử lý chuỗi trước (sau) số. Nhưng về cơ bản, bạn có thể thực hiện bất kỳ kết hợp regex nào + printf miễn là awk của bạn hỗ trợ nó. Và nó cũng hỗ trợ các ký tự khoảng trắng (ngoại trừ dòng mới) trong tên tập tin.

for f in *.txt ;do 
    mv "$f" "$( 
     awk -v f="$f" '{ 
      if (match(f, /^([a-zA-Z_-]*)([0-9]+)(\..+)/, a)) { 
       printf("%s%04d%s", a[1], a[2], a[3]) 
      } else { 
       print(f) 
      } 
     }' <<<'' 
    )" 
done 
+0

Tôi vừa thử ở trên và nó thổi đi tất cả các tệp trong thư mục và để lại một tệp "0000". – Ryan

+0

@Ryan Điều đó có nghĩa là regex không khớp với bất kỳ tệp nào trong thư mục của bạn. Bạn phải tùy chỉnh regex + printf để hoàn thành công việc. Đoạn mã trên chỉ là một ví dụ. – rindeal

+0

rindeal là chính xác. Khi tôi sửa chữa regex cho tên tập tin của tôi (tôi đã có không gian) nó làm việc. Các tên tệp không phù hợp với regex vẫn được chuyển sang '0000' có thể gây ngạc nhiên một chút. Nếu bạn đang thực hiện đổi tên hàng loạt và sẽ thử các tập lệnh ngẫu nhiên mà bạn tìm thấy trên SO, bạn tốt hơn nên có một bản sao lưu. – Ryan

0

Để cung cấp một giải pháp đó là một cách thận trọng ghi vào là đúng ngay cả trong sự hiện diện của tên tập tin với không gian:

#!/usr/bin/env bash 

pattern='%04d' # pad with four digits: change this to taste 

# enable extglob syntax: +([[:digit:]]) means "one or more digits" 
# enable the nullglob flag: If no matches exist, a glob returns nothing (not itself). 
shopt -s extglob nullglob 

for f in [[:digit:]]*; do    # iterate over filenames that start with digits 
    suffix=${f##+([[:digit:]])}   # find the suffix (everything after the last digit) 
    number=${f%"$suffix"}     # find the number (everything before the suffix) 
    printf -v new "$pattern" "$number" "$suffix" # pad the number, then append the suffix 
    if [[ $f != "$new" ]]; then     # if the result differs from the old name 
    mv -- "$f" "$new"       # ...then rename the file. 
    fi 
done 
Các vấn đề liên quan