Linux-shellscript om voorloopnullen aan bestandsnamen toe te voegen

Ik heb een map met ongeveer 1.700 bestanden. Ze hebben allemaal de naam 1.txtof 1497.txt, enz. Ik wil alle bestanden hernoemen zodat alle bestandsnamen vier cijfers lang zijn.

D.w.z. 23.txtwordt 0023.txt.

Wat is een shellscript dat dit doet? Of een gerelateerde vraag: Hoe gebruik ik grep om alleen regels te matchen die \d.txtbevatten (dwz één cijfer, dan een punt, dan de letters txt)?

Dit is wat ik tot nu toe heb:

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

Voer dat in principe drie keer uit, met opdrachten om een ​​cijfer, twee cijfers en driecijferige bestandsnamen te vinden (waarbij het aantal beginnullen is gewijzigd).


Antwoord 1, autoriteit 100%

Probeer:

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

Wijzig het bestandsnaampatroon ([0-9]*.txt) indien nodig.


Een algemene hernoemde naam die geen aannames doet over de initiële set bestandsnamen:

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

Over hetzelfde onderwerp:


Antwoord 2, autoriteit 31%

Met behulp van het rename(prenamein sommige gevallen) script dat soms met Perl is geïnstalleerd, kunt u Perl-expressies gebruiken om de hernoeming uit te voeren. Het script slaat het hernoemen over als er een naambotsing is.

De onderstaande opdracht hernoemt alleen bestanden met vier of minder cijfers gevolgd door de extensie “.txt”. Het hernoemt geen bestanden die niet strikt aan dat patroon voldoen. Namen die uit meer dan vier cijfers bestaan, worden niet afgekapt.

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

Een paar voorbeelden:

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

Andere antwoorden die tot nu toe zijn gegeven, zullen proberen bestanden te hernoemen die niet aan het patroon voldoen, fouten te produceren voor bestandsnamen die niet-cijferige tekens bevatten, hernoemingen uit te voeren die naambotsingen veroorzaken, proberen en falen om bestanden te hernoemen met spaties in hun namen en mogelijk andere problemen.


Antwoord 3, autoriteit 26%

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

Antwoord 4, autoriteit 17%

One-liner:

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

Hoe gebruik ik grep om alleen regels te matchen die \d.txt bevatten (IE 1 cijfer, dan een punt, dan de letters txt)?

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

Antwoord 5, autoriteit 9%

Laten we aannemen dat je bestanden met datatype .dat in je map hebt staan. Kopieer deze code gewoon naar een bestand met de naam run.sh, maak het uitvoerbaar door chmode +x run.shuit te voeren en voer het vervolgens uit met ./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

Hiermee worden alle bestanden in uw map geconverteerd naar filename_00000.dat, filename_00001.dat, enz.


Antwoord 6, autoriteit 2%

Deze versie ondersteunt ook het verwerken van strings voor (na) het nummer. Maar in principe kun je elke regex-matching+printf doen, zolang je awk dit ondersteunt. En het ondersteunt ook witruimtetekens (behalve nieuwe regels) in bestandsnamen.

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

Antwoord 7

Als u alleen tekstbestanden met één cijfer wilt matchen, kunt u het volgende doen…

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

Antwoord 8

Hint in één zin:

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

Antwoord 9

Om een ​​oplossing te bieden die zorgvuldig is geschreven om correct te zijn, zelfs in de aanwezigheid van bestandsnamen met spaties:

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

Antwoord 10

Er is standaard een rename.ulcommando geïnstalleerd vanuit het util-linuxpakket (tenminste in Ubuntu).

Het gebruik is (do a man rename.ul):

hernoem [opties] expressievervangingsbestand…

De opdracht vervangt de eerste keer dat expressionvoorkomt door de gegeven replacementvoor de geleverde bestanden.

Terwijl je het commando vormt, kun je het volgende gebruiken:

rename.ul -nv replace-me with-this in-all?-these-files*

om geen wijzigingen aan te brengen, maar om te lezen welke wijzigingen dat commando zou aanbrengen. Als je zeker weet, voer je de opdracht opnieuw uit zonder de opties -v (uitgebreid) en -n (no-act)

in jouw geval zijn de commando’s:

rename.ul "" 000 ?.txt
rename.ul "" 00 ??.txt
rename.ul "" 0 ???.txt

Other episodes