Diskussion [SH] Suffix an Dateinamen anhängen - Codereview

Mat

Aktives Mitglied
Ich versuche, so 1 mal die Woche alten Gammelcode aus Uniaufgaben und Projekten zu posten.

Dieses Mal eine Shellscriptaufgabe. Ziel war es, den Aufbau von Shellscripts kennenzulernen und mit Parametern zu arbeiten.

Aufgabe war:
  1. Suffixe an alle Dateien des aktuellen Verzeichnisses anhängen
  2. In Anlehnung an Systemskripte Parameter und Hilfetext basteln (aber keine Manpage)
  3. Bash erzwingen

Bash:
#!/usr/bin/env bash
# Append suffixes to filenames

# Show usage info
usage() {
    echo "
    USAGE: $0 [OPTION] [<string>]
        Appends a given suffix to all files in the current directoy.
    OPTIONS:
        -h | --help     : Shows this
        -p | --preview  : Just preview the changes
        -r | --rename   : Change the file names

    EXAMPLE:
        $ ls ./
        x y z
        $ $0 --rename '.csv'
        $ ls .
        x.csv y.csv z.csv
    "
}

# Show an error if suffix is empty.
check_suffix() {
    if [ "${file_suffix:-}" = "" ]; then
        echo "--- empty suffix!"
        usage
        exit 1
    fi
}

# Shows a preview of the rename action
preview() {
    check_suffix
    for file in $(ls .); do
        if [[ "./$file" != "$0" ]]; then
            echo $file" --> "$file"${file_suffix}"
        fi
    done
    echo
}

# Rename the files
rename() {
    check_suffix
    preview
    counter=0
    for file in $(ls .); do
        if [[ "./$file" != "$0" ]]; then
            mv $file $file"${file_suffix}"
            counter=$((counter + 1))
        fi
    done
    echo "$counter files renamed"
    echo
}

# --- main ---

# Check args count
if [ $# -gt 2 ]; then
    echo
    echo "--- Invalid number of arguments!"
    usage
    exit 1
fi

case $1 in
"")
    echo
    echo "--- Empty argument!"
    usage
    exit 1
    ;;
"-h")
    echo
    echo "--- Showing usage info"
    usage
    exit 0
    ;;
"--help")
    echo
    echo "--- Showing usage info"
    usage
    exit 0
    ;;
"-r")
    echo
    echo "--- Renaming:"
    file_suffix=$2
    rename
    exit 0
    ;;
"--rename")
    echo
    echo "--- Renaming:"
    file_suffix=$2
    rename
    exit 0
    ;;
"-p")
    echo
    echo "--- Preview:"
    file_suffix=$2
    preview
    exit 0
    ;;
"--preview")
    echo
    echo "--- Preview:"
    file_suffix=$2
    preview
    exit 0
    ;;
*)
    echo
    echo "--- Unknown argument: '$1'"
    usage
    ;;
esac

exit 0

Jetzt wo ich das wieder sehe, sieht das ok aus, auch wenn die Funktion nicht sehr nützlich ist. Ohne die Anforderungen hätte das auch ein 1Zeiler werden können.
.
  1. Der doppelte Code bei preview und rename gefällt mir nicht
  2. Vielleicht könnte man noch den Switchcase kleiner machen
  3. Ich glaube, so wie das aussieht, werden auch Ordner umbenannt
Vielleicht fällt ja jemandem noch ein weiteres Problem auf.
 
Oh, bash ist auch für mich immer noch Neuland.

Suffixe an alle Dateien des aktuellen Verzeichnisses anhängen
Hmm. Und wenn das Script im Arbeitsverzeichnis liegt, wird das auch umbenannt. Hätte man anders regeln können. Aber gut, ist halt die Aufgabenstellung.


Der doppelte Code bei preview und rename gefällt mir nicht
Finde ich kein Problem. Aber preview aus rename aufzurufen erzeugt Overhead.


Vielleicht könnte man noch den Switchcase kleiner machen
Ja, da gibt's ein ODER.


Ich glaube, so wie das aussieht, werden auch Ordner umbenannt
Könntest find statt ls nutzen.


Für den Anfang vielleicht so?
Bash:
#!/usr/bin/env bash
# Append suffixes to filenames

# Show usage info
usage() {
    echo "
    USAGE: $0 [OPTION] [<string>]
        Appends a given suffix to all files in the current directoy.
    OPTIONS:
        -h | --help     : Shows this
        -p | --preview  : Just preview the changes
        -r | --rename   : Change the file names

    EXAMPLE:
        $ ls ./
        x y z
        $ $0 --rename '.csv'
        $ ls .
        x.csv y.csv z.csv
    "
}

# Show an error if suffix is empty.
check_suffix() {
    if [ "${file_suffix:-}" = "" ]; then
        echo "--- empty suffix!"
        usage
        exit 1
    fi
}

# Shows a preview of the rename action
preview() {
    check_suffix
    for file in $(find . -maxdepth 1 -type f); do # *** Nur Dateien listen.
        if [[ "./$file" != "$0" ]]; then
            echo $file" --> "$file"${file_suffix}"
        fi
    done
    echo
}

# Rename the files
rename() {
    check_suffix
    # preview *** 2x check suffix, 2x Dateien listen und 2x iterieren ...
    counter=0
    for file in $(find . -maxdepth 1 -type f); do
        if [[ "./$file" != "$0" ]]; then
            echo $file" --> "$file"${file_suffix}" # *** ... besser das echo aus preview hierher zu übernehmen als preview aufzurufen
            mv $file $file"${file_suffix}"
            counter=$((counter + 1))
        fi
    done
    echo "$counter files renamed"
    echo
}

# --- main ---

# Check args count
if [ $# -gt 2 ]; then
    echo
    echo "--- Invalid number of arguments!"
    usage
    exit 1
fi

case $1 in
"")
    echo
    echo "--- Empty argument!"
    usage
    exit 1
    ;;
"-h" | "--help") # Vertical Bar fungiert als ODER
    echo
    echo "--- Showing usage info"
    usage
    exit 0
    ;;
"-r" | "--rename")
    echo
    echo "--- Renaming:"
    file_suffix=$2
    rename
    exit 0
    ;;
"-p" | "--preview")
    echo
    echo "--- Preview:"
    file_suffix=$2
    preview
    exit 0
    ;;
*)
    echo
    echo "--- Unknown argument: '$1'"
    usage
    ;;
esac

exit 0
 
Naja, der weitere Teil der Aufgabe war dann, sich mit PATH vertraut zu machen und das Skript dauerhaft hinzuzufügen. Bisschen Bash-Profile war auch noch dabei. Aber der Codeteil war das einzige, was sich gut (und leicht ^^) übertragen ließ.

Ja, da gibt's ein ODER.
Ahh.. wusste nicht, dass da ein Oder unterstützt wird, cool.

Könntest find statt ls nutzen.
Das ist etwas, was ich bei ls erwartet hätte. Aber find ist auch gut

Finde ich kein Problem. Aber preview aus rename aufzurufen erzeugt Overhead.
Stimmt.. und das für nur eine Zeile

Hmm. Und wenn das Script im Arbeitsverzeichnis liegt, wird das auch umbenannt. Hätte man anders regeln können. Aber gut, ist halt die Aufgabenstellung.
Hahaa! Da habe ich damals dran gedacht! Das passiert nämlich nicht: if [[ "./$file" != "$0" ]]; :geek:
Das wird wohl im geänderten Code mit umbenannt, weil find die Dateinamen schon in der Form ./datei liefert. Nach einer Änderung zu if [[ $file != "$0" ]]; gehts auch damit.


Danke dir. Weil ich eher selten was mit Bash mache, habe ich mir Bashnotizen gemacht und da kommt das mit rein als Beispiel.
 
Bash:
#!/usr/bin/env bash

# Append suffixes to filenames

# Show usage info
usage() {
    echo "
    USAGE: $0 [OPTION] [<string>]
        Appends a given suffix to all files in the current directoy.
    OPTIONS:
        -h | --help     : Shows this
        -p | --preview  : Just preview the changes
        -r | --rename   : Change the file names

    EXAMPLE:
        $ ls ./
        x y z
        $ $0 --rename '.csv'
        $ ls .
        x.csv y.csv z.csv
    "
}

# Show an error if suffix is empty.
check_suffix() {
    if [ "${file_suffix:-}" = "" ]; then
        echo "--- empty suffix!"
        usage && exit 1
    fi
}


# Rename the files
rename() {
    preview=$1 # Shows a preview of the rename action
    check_suffix
    # preview *** 2x check suffix, 2x Dateien listen und 2x iterieren ...
    counter=0
    for file in $(find . -maxdepth 1 -type f); do
        if [[ "$file" != "$0" ]]; then
            echo $file" --> "$file"${file_suffix}" # *** ... besser das echo aus preview hierher zu übernehmen als preview aufzurufen
             [[ "x$1" == "x0" ]] && : || mv $file $file"${file_suffix}"
            counter=$((counter + 1))
        fi
    done
    echo "$counter files renamed"
    echo
}

# --- main ---

# Check args count
if [ $# -gt 2 ]; then
    echo
    echo "--- Invalid number of arguments!"
    usage && exit 1
fi

case $1 in
"")
    echo
    echo "--- Empty argument!"
    usage && exit 1
    ;;
"-h" | "--help") # Vertical Bar fungiert als ODER
    echo
    echo "--- Showing usage info"
    usage && exit 0
    ;;
"-r" | "--rename")
    echo
    echo "--- Renaming:"
    file_suffix=$2
    rename && exit 0
    ;;
"-p" | "--preview")
    echo
    echo "--- Preview:"
    file_suffix=$2
    rename '0' && exit 0
    ;;
*)
    echo
    echo "--- Unknown argument: '$1'"
    usage && exit 1
    ;;
esac

exit 0
 
Zuletzt bearbeitet:
Yeah, überall nochmal lauter Zeilen gespart. :D


Bash:
rename() {
    preview=$1
    counter=0
    for file in $(find . -maxdepth 1 -type f); do
        if [[ "$file" != "$0" ]]; then
            echo $file" --> "$file"${file_suffix}"
             [[ "x$1" == "x0" ]] && : || mv $file $file"${file_suffix}"
            counter=$((counter + 1))
        fi
    done
    echo "$counter files renamed"
    echo
}
[...]
"-p" | "--preview")
    echo
    echo "--- Preview:"
    file_suffix=$2
    rename '0' && exit 0
    ;;

2+19: Ich wusste gar nicht, dass man Bashfunktionen auf diese Weise Argumente übergeben kann. Das ist ja wie beim Skriptaufruf selber.

7: Kannst du das für mich aufschlüsseln? So habe ich das verstanden:
Bash:
 [[ "x$1" == "x0" ]]   \       # wenn 0
&&                     \       # dann führe nächste Anweisung aus
: ||                   \       # Mache ein Smiley
mv $file $file"${file_suffix}" # Benenne Dateien um
 
Ich kann übrigens nur empfehlen, ShellCheck über solche Skripte laufen zu lassen. Nutze ich selbst auch, sogar in automatisierter Form für meine GitHub-Repositories: CodeFactor verwendet ShellCheck intern für seine Analysen und zeigt mir eventuelle Probleme an, wenn ich einen PR erstelle:

1594117671501.png


Diese Probleme kann ich mir dann in CodeFactor genauer anschauen ...

1594117733403.png


... und ShellCheck liefert mir eine ziemlich gute Fehlerbeschreibung.

1594117777075.png
 
Cool, kennst du sowas Ähnliches auch für Powershell?

Edit: Ah, Codefactor hat auch Powershell, ok
 
Zurück
Oben Unten