Перейменування файлів, щоб додати суфікс


13

Мені потрібна команда для перейменування всіх файлів у поточній робочій директорії таким чином, що нове ім'я файлу буде таким же, як і старе, але включає суфікс, що відповідає кількості рядків вихідних файлів (наприклад, якщо файл fмає 10 рядки, то його слід перейменувати на f_10).

Ось моя (неробоча) спроба:

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

Ви могли б зробити таку відповідь! (Якщо він додає щось нове до існуючих відповідей - але, схоже, так і є)
Volker Siegel,

Відповіді:


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

Дякую тердон! цей командний рядок здається виконати роботу, але як я можу змінити крапку (.) на (_)? Крім того, оскільки мій сценарій знаходиться всередині папки, його також перейменовують, а отже, дозволяє виконувати мій сценарій один раз (тому що ім'я сценарію змінюється ...)
Martin Yeboah

@MartinYeboah див. Оновлену відповідь на _. Що стосується сценарію, який сценарій? Це слід запускати з командного рядка, сценарій не потребує. Якщо ви хочете, щоб він відповідав лише деяким файлам, змініть in *на, наприклад, in *txtчи щось.
тердон,

велике спасибі;) я повністю забув, що він повинен бути виконаний з командного рядка :)
Martin Yeboah

Я думаю, що wc -l < $fзамість грепу було б легше зрозуміти (і, можливо, краще виконати, але я цього не перевірив).
musiKk

@musiKk так, але оскільки використовуються інші відповіді wc, я хотів показати інший підхід. Але гаразд, досить справедливо.
тердон

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

renameчудовий =) +1
AB

1
Не вдалося б цього провести на abcd? Змініть другу групу захоплення на (\.?[^\.]+).
ps95

@ prakharsingh95 Це правда, однак (\.?[^\.]+)це також не нормально, оскільки вона відповідатиме лише другій крапці і не збігатиметься з іменем файлу з послідовними крапками або закінчується крапкою незалежно. Це нелегке важке рішення, єдиний спосіб, здається, зробити дві заміни.
kos

@kos ви маєте рацію. Як щодо ([^ \.] +). *? ([^ \.] + $) Я не впевнений у оптимальності. Робоча скрипка: regex101.com/r/rQ9lX1/1
ps95

1
@ prakharsingh95 ви не хочете бігти .всередині класів символів.
тердон

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 Стара звичка: \
AB

3

Просто для розваги і хихикає рішенням rename. Оскільки renameце інструмент Perl, який приймає довільну рядок, що є eval'd, ви можете робити всілякі шнанігани. Рішення, яке, здається, працює:

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

Особлива подяка тердону та Геліо за перегляд сценарію та запропоновані зміни


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}та просто використовуючи розширення, як є.

Для обробки точкових файлів ви можете використовувати 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: Я не зміг би пояснити команду. ;-)
Геліо
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.