Zmieniasz nazwę pliku z datownikiem zmodyfikowanym datą na końcu nazwy pliku?

14

Powiedzmy, że mam katalog z wieloma plikami, takimi jak g.txt, gdzie g.txt został ostatnio zmodyfikowany, powiedzmy, 20 czerwca 2012 r.

Jak mam zmienić nazwę partii wszystkich plików (takich jak g.txt) z dołączoną na końcu datą ostatniej modyfikacji 20 czerwca 2012 r.?

InquilineKea
źródło

Odpowiedzi:

13

Szybki i brudny Bash one-liner do zmiany nazw wszystkich (globbed) plików w bieżącym katalogu z filename.txtna filename.txt-20120620:

for f in *; do mv -- "$f" "$f-$(stat -c %Y "$f" | date +%Y%m%d)"; done

Jestem pewien, że przedsiębiorczy kujon Bash znajdzie coś dla siebie. :)

Oczywiście nie robi to pożądanych rzeczy, takich jak sprawdzenie, czy plik ma już na końcu coś, co wygląda jak data.

jgoldschrafe
źródło
2
+1, wygląda dobrze. możesz uczynić go trochę bardziej niezawodnym, używając „-” jako pierwszego argumentu do mv. chroni przed filenami zaczynającymi się na „-”
cas
5
Co to za dateimplementacja? Mój GNU datewydaje się nie obsługiwać danych wejściowych.
manatwork
coreutils 8.4 na RHEL 6.
jgoldschrafe
2
@jgoldschrafe, czy jesteś pewien, że kod działa poprawnie dla Ciebie? pastebin.com/nNYubf3A
manatwork
5
dobre warunki połowów. moja data GNU 8.13 również nie obsługuje odczytu ze standardowego wejścia. Obsługuje użycie czasu modyfikacji pliku z „-r” - np. „Data +% Y% m% d -r $ f”, więc statystyki nie są nawet potrzebne w tym konkretnym przypadku.
cas
18

oto wersja jednowierszowej goldschrafe, która:

  • nie używa statystyki
  • współpracuje z wcześniejszymi wersjami daty GNU
  • poprawnie radzi sobie z dowolnymi spacjami w nazwach plików
  • radzi sobie także z nazwami plików zaczynającymi się od myślnika

    for f in *; do mv -- "$f" "$f-$(date -r "$f" +%Y%m%d)"; done

cas
źródło
1
Powinieneś to zrobić, date -r "$f" +%Y%m%dinaczej nie będzie działać, jeśli POSIXLY_CORRECTjest w środowisku. Zasadniczo opcje powinny poprzedzać inne argumenty.
Stéphane Chazelas
powinna to być „poprawna odpowiedź”
nieprawidłowa nazwa użytkownika
Oczywiście nie potrzebujesz aparatów ortodontycznych "${f}".
G-Man mówi „Przywróć Monikę”
ale jak sprawiłbyś, że daty, które wcześniej przygotowaliśmy, np. „Ymd-filename”?
timebandit
2

Obowiązkowy zsh one-liner (nie licząc jednorazowego obciążenia opcjonalnych komponentów):

zmodload zsh/stat
autoload -U zmv
zmv -n '(*)' '$1-$(stat -F %Y%m%d +mtime -- $1)'

Używamy statwbudowanego zsh/statmodułu i zmvfunkcji do zmiany nazw plików. A oto dodatek, który umieszcza datę przed rozszerzeniem, jeśli istnieje.

zmv -n '(*)' '$1:r-$(stat -F %Y%m%d +mtime -- $1)${${1:e}:+.$1:e}'
Gilles „SO- przestań być zły”
źródło
1

Jak zrozumiałem, nie wiemy z góry, jaka jest data modyfikacji. Musimy więc pobrać go z każdego pliku, sformatować dane wyjściowe i zmienić nazwę każdego pliku w taki sposób, aby zawierał datę modyfikacji w nazwach plików.

Możesz zapisać ten skrypt jako coś takiego jak „modif_date.sh” i uczynić go wykonywalnym. Wywołujemy go z katalogiem docelowym jako argumentem:

modif_date.sh txt_collection

Gdzie „txt_collection” to nazwa katalogu, w którym mamy wszystkie pliki, których nazwę chcemy zmienić.

#!/bin/sh

# Override any locale setting to get known month names
export LC_ALL=c
# First we check for the argument
if [ -z "$1" ]; then
    echo "Usage: $0 directory"
    exit 1
fi

# Here we check if the argument is an absolute or relative path. It works both ways
case "${1}" in
  /*) work_dir=${1};;
  *) work_dir=${PWD}/${1};;
esac

# We need a for loop to treat file by file inside our target directory
for i in *; do
    # If the modification date is in the same year, "ls -l" shows us the timestamp.
    # So in this case we use our current year. 
    test_year=`ls -Ggl "${work_dir}/${i}" | awk '{ print $6 }'`
    case ${test_year} in *:*) 
        modif_year=`date '+%Y'`
        ;;
    *)
        modif_year=${test_year}
        ;;
    esac
    # The month output from "ls -l" is in short names. We convert it to numbers.
    name_month=`ls -Ggl "${work_dir}/${i}" | awk '{ print $4 }'`
    case ${name_month} in
            Jan) num_month=01 ;;
            Feb) num_month=02 ;;
        Mar) num_month=03 ;;
        Apr) num_month=04 ;;
        May) num_month=05 ;;
        Jun) num_month=06 ;;
        Jul) num_month=07 ;;
        Aug) num_month=08 ;;
        Sep) num_month=09 ;;
        Oct) num_month=10 ;;
        Nov) num_month=11 ;;
        Dec) num_month=12 ;;
        *) echo "ERROR!"; exit 1 ;;
    esac
    # Here is the date we will use for each file
    modif_date=`ls -Ggl "${work_dir}/${i}" | awk '{ print $5 }'`${num_month}${modif_year}
    # And finally, here we actually rename each file to include
    # the last modification date as part of the filename.
    mv "${work_dir}/${i}" "${work_dir}/${i}-${modif_date}"
done
Aline
źródło
1
przeczytaj stronę manuala dla stat (1), aby dowiedzieć się, jak możesz zmniejszyć swój skrypt o około 3/4 ... większość z powyższych polega na ponownym wynalezieniu koła. w szczególności „stat -c% Y” da ci czas modyfikacji pliku w sekundach od epoki (1970-01-01 00:00:00). Można go następnie wykorzystać jako dane wejściowe do daty (1), aby sformatować znacznik czasu zgodnie z wymaganiami. na przykład patrz odpowiedź jgoldschrafe powyżej.
cas
@CraigSanders Plusem jest to, że ten skrypt działa w systemach operacyjnych innych niż Linux, które mają inne statnarzędzie lub nie mają go wcale.
Gilles „SO- przestań być zły”
Zauważ, że parsowanie wyniku lsnie jest niezawodne . W niektórych wariantach uniksowych nazwy użytkowników i grup mogą zawierać spacje, co zignoruje wyrównanie kolumn dat.
Gilles „SO- przestań być zły”
@ giles: prawda, ale każdy rozsądny :-) zainstalowałby GNU coreutils (i wszystkie inne narzędzia GNU) na dowolnym systemie innym niż Linux. Jest to najprostszy sposób na uzyskanie nie tylko dobrego zestawu narzędzi dla użytkowników, ale także spójnego zestawu niezależnie od jądra.
cas
1
(Ciąg dalszy)… (5) Kolejny błąd: zakłada, że ​​każda data / godzina wyświetlana ls jako data i godzina (a nie data i rok) muszą przypadać w bieżącym roku. To nie jest prawda. To jest w ciągu ostatnich sześciu miesięcy; może to być rok poprzedni (np. od 27 września 2016 r. do 31 grudnia 2016 r. minęło sześć miesięcy). (6) Ryzykując papugowanie Wiki Grega (który już cytował @Gilles), nazwy plików zawierające znaki nowej linii i spacje mogą spowodować, że to się nie powiedzie. … (Ciąg dalszy)
G-Man mówi „Przywróć Monikę”
0

Oto wersja jednowierszowego cas (oparta na oneliner goldschrafe) rozbudowana o idempotencję ,

tzn. rozszerzony na pliki prefiksów z datą i czasem i tylko w przypadku tych, którzy nie mają jeszcze prefiksu daty .

Przypadek użycia: pomocny, jeśli dodajesz nowe pliki do katalogu i chcesz dodać prefiks daty do tych, które jeszcze go nie mają.

for f in * ; do
  if [[ "$f" != ????-??-??' '??:??:??' - '* ]]; then
    mv -v -- "$f" "$(date -r "$f" +%Y-%m-%d' '%H:%M:%S) - $f" ;
  fi;
done
Grzegorz Wierzowiecki
źródło
Jeśli znaczniki czasowe plików są wkręcone i są plikami JPEG, możesz chcieć, aby jodły naprawiły je danymi EXIF: for f in *.jpg ; do jhead -ft "$f" ; doneźródło: unix.stackexchange.com/a/290755/9689
Grzegorz