2016-07-29 39 views
1

Ich möchte Bash ausführen rm -i *, wenn ich rm * eingeben, aber sonst normal rm laufen. Wichtig ist, dass ich nicht jedes Mal rm -i ausführen möchte, wenn ich einen Platzhalter wie rm part* verwende. Hier ist so weit, wie ich mir vorstellen konnte:Wie man "*" als Argument zur bash-Funktion erfasst und in einem Vergleich verwendet

rm() 
{ 
    if [ "$1" == "*" ]; then 
     rm -i * 
    else 
     rm $1 
    fi 
} 

Aber ich weiß, das wird scheitern. Ich weiß, dass der Vergleich, den ich möchte, ist ^*$, aber ich weiß nicht, wie man es umsetzt.

+4

Zu der Zeit, Ihre 'rm' Funktion ausgeführt wird die '*' wird bereits erweitert. – Paulpro

+3

Das Problem ist, dass 'rm' nicht' * 'als Argument bekommt; es erhält die lange Liste von Dateien, die die Shell um '*' erweitert, als Argumente. – chepner

+5

GNU 'rm' hat eine' -I' Option, die Sie nur auffordert, wenn Sie mehr als 3 Dateien entfernen. – chepner

Antwort

7

Es ist buchstäblich unmöglich zu wissen, ob Ihr Befehl mit einem Platzhalter ohne die Mitarbeit Ihrer Shell aufgerufen wurde.

Wenn Sie rufen rm * (wie jeder anderer Befehl), die * mit einer Liste von Dateinamen vor Aufruf ersetzt wird. Wenn also innerhalb des Befehls die Information, dass es einen Platzhalter erhalten hat, nicht mehr existiert, wurden $1, $2 usw. durch eine Liste von Namen ersetzt, auf die der Platzhalter erweitert wurde.


das gesagt ist, da wir ein Shell-Funktion, die Zusammenarbeit unserer Schale sind tatsächlich verfügbar ist:

rm() { 
    local cmd 
    read -r _ cmd < <(HISTTIMEFORMAT=''; history 1) 
    if [[ $cmd = "rm *" ]]; then 
    command rm -i "[email protected]" 
    else 
    command rm "[email protected]" 
    fi 
} 

Wie funktionierts?

  • history 1 gibt den letzten Befehl in der Shell-Historie zurück (mit einer vorangestellten Zahl).
  • read -r _ cmd liest diese Zahl in die Variable _, und den Rest der Befehlszeile in die Variable cmd
  • [[ $cmd = "rm *" ]] vergleicht den Befehl für diese genaue Zeichenfolge
  • command rm ... die externenrm Befehl ausgeführt wird, um die Rekursion zu vermeiden zurück unsere Funktion wieder.
  • +0

    Dies funktioniert möglicherweise in einigen Fällen nicht. Ich habe 'HISTTIMEFORMAT = "[% F% T]" 'in meine Shell exportiert und es schlägt fehl.Wahrscheinlich kann sich die Bedingung ändern in '[[$ cmd == *" rm * "]]' – anubhava

    +0

    Nein, das habe ich nicht gemeint. In der aktuellen Form hat diese Funktion 'rm -i ...' nicht ausgeführt, weil ich HISTTIMEFORMAT = "[% F% T]" in meinem '.bashrc' exportiert hatte, was dazu führte, dass' history 1' '49370 ausgab [2016-07-29 15:42:52] rm * '. Deshalb schlug ich vor, '[[$ cmd == * rm *"]] 'könnte funktionieren – anubhava

    +1

    * facepalm * - Ich habe verpasst, dass' * "rm *" 'am Ende verankert ist. Yup, das macht vollkommen Sinn. –

    1

    Da Sie nicht wissen können, ob es einen Platzhalter gibt, warum nicht die Anzahl der Argumente überprüfen?

    Zum Beispiel:

    #!/bin/bash 
    rm() { 
        if [ "$#" -gt 1 ]; then 
         echo command rm -i "[email protected]" 
        else 
         echo command rm "[email protected]" 
        fi 
    } 
    rm a b c 
    rm a 
    
    +0

    ... aber du weißt nicht, ob du 'a' bekommst, weil das' '' heißt, oder 'a', weil das der Benutzer hat. –

    +2

    @CharlesDuffy: Das stimmt. Aber ich denke, der Anwendungsfall ist es zu warnen, wenn mehrere Dateien gelöscht werden, so dass es eine gültige Alternative für das OP sein kann. – user000001

    +0

    Ich liebe die Eleganz der Lösung. Es kommt tatsächlich auf den Kern der Sache - verhindert, dass ich mehr als eine Datei entfernen (oder welche Nummer ich dort hineinlege). Aber ich denke, es ist insgesamt sicherer, den Befehl tatsächlich zu erfassen. Gute Arbeit! – abalter