การเปลี่ยนชื่อไฟล์เพื่อเพิ่มคำต่อท้าย


13

ฉันต้องการคำสั่งเพื่อเปลี่ยนชื่อไฟล์ทั้งหมดในไดเรกทอรีการทำงานปัจจุบันในทางที่ชื่อไฟล์ใหม่จะเหมือนเดิม แต่รวมถึงคำต่อท้ายที่สอดคล้องกับจำนวนบรรทัดของไฟล์ต้นฉบับ (เช่นถ้าไฟล์fมี 10 บรรทัดจากนั้นควรเปลี่ยนชื่อเป็นf_10)

นี่คือความพยายามของฉัน (ไม่ทำงาน):

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

คุณสามารถตอบได้! (ถ้าจะเพิ่มสิ่งใหม่ ๆ เพื่อตอบมีอยู่ - แต่ดูเหมือนว่ามันไม่)
Volker ซีเกล

คำตอบ:


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

@MartinYeboah _ดูปรับปรุงคำตอบสำหรับ สำหรับสคริปต์แล้วสคริปต์อะไร ที่ควรจะเรียกใช้จากบรรทัดคำสั่งไม่จำเป็นต้องมีสคริปต์ หากคุณต้องการให้ตรงกับไฟล์บางไฟล์ให้เปลี่ยนเป็นin *ตัวอย่างin *txtหรือบางอย่าง
terdon

ขอบคุณมาก;) ฉันทั้งหมดลืมว่ามันควรจะดำเนินการจากบรรทัดคำสั่ง :)
มาร์ติน Yeboah

ฉันคิดว่าwc -l < $fแทนที่จะเป็น grep จะเข้าใจง่ายกว่า (และอาจจะดีกว่าในการแสดง แต่ฉันไม่ได้ตรวจสอบมัน)
musiKk

@musiKk ใช่ แต่เนื่องจากมีคำตอบอื่น ๆ ที่ใช้wcฉันต้องการแสดงวิธีการที่แตกต่างกัน แต่ตกลงพอยุติธรรม
terdon

10

คุณสามารถลองซับนี้:

find . -maxdepth 1 -type f -exec bash -c 'mv -i "$1" "$1.$(wc -l <"$1")"' _ {} \;
  • นี่จะค้นหาไฟล์ทั้งหมดในไดเรกทอรีทำงานปัจจุบัน ( find . -maxdepth 1 -type f)

  • จากนั้นเรากำลังเรียกใช้เชลล์อินสแตนซ์เหนือไฟล์ที่พบเพื่อเปลี่ยนชื่อไฟล์เพื่อต่อท้ายจำนวนบรรทัด

ตัวอย่าง:

$ 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

renamegreat =) +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

1
@kos Old นิสัย: \
AB

3

เพียงเพื่อความสนุกสนานและ giggles renameโซลูชั่นที่มี ตั้งแต่renameเป็นเครื่องมือ Perl ที่ยอมรับสตริงที่กำหนดเองซึ่งคุณสามารถทำทุกประเภทของ shenanigans วิธีแก้ปัญหาที่ดูเหมือนว่าจะใช้งานได้มีดังต่อไปนี้:

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

แนวคิดที่น่าสนใจ +1
AB

2

ซอลเบลโลว์ร้องครอบคลุมหลายกรณี: จุดและนามสกุลเดียว (file.txt), หลายจุดและนามสกุล (file.1.txt), จุดต่อเนื่อง (file..foobar.txt) และจุดในชื่อไฟล์ (ไฟล์หรือ ไฟล์..).

บท

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

โปรดทราบว่าไม่มีบรรทัดในไฟล์ และไฟล์ .. ดังนั้นการนับบรรทัดคือ 0

ขอขอบคุณเป็นพิเศษสำหรับ terdon และ Helio สำหรับการตรวจสอบสคริปต์และการแก้ไขที่แนะนำ


2

อีกวิธีทุบตีพัฒนาด้วย@Helio ในการแชท :

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อาร์เรย์จะว่างเปล่า เราสามารถใช้ประโยชน์จากสิ่งนี้ได้โดยใช้ค่าเริ่มต้นสำหรับชื่อไฟล์${BASH_REMATCH[1]:-$file}และเพียงแค่ใช้ส่วนขยายตามที่เป็นอยู่

เพื่อจัดการไฟล์ dot คุณสามารถใช้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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.