2017-10-26 5 views
4

frage ich mich, warum ich se gleiche Leistung erhalten nicht aus:Bash: Subshell Verhalten von ls

ls -1 -tF | head -n 1

und

echo $(ls -1 -tF | head -n 1)

Ich habe versucht, die letzte geänderte Datei zu erhalten, aber benutze ich es in einer Subshell manchmal bekomme ich mehr als eine Datei als Ergebnis?

Warum und wie zu vermeiden?

+0

ich ls -tr | Tail - n1 und das funktioniert immer .. – MostWanted

+1

zitieren Sie Ihre Subshell, es wird mit 'file *' für ausführbare Dateien gleichgesetzt, die dann vor dem Echo erweitert wird. '-F, --classify Append-Indikator (eines von */=> @ |) an Einträge' – 123

+0

Hier die Erklärung für die -F:' Funktion L { myvar = $ 1; h = $ {myvar: = "1"}; echo "letzte $ {h} modifizierte Datei (en):"; export L = $ (ls -1 -tF | fgrep -v/| head -n $ {h} | sed 's \ (\ * \ | = \ | @ \) $ // g'); ls -l $ L; } alias ol = 'L; xdg-open $ L ' ' –

Antwort

0

Ich habe gerade den Fehler gefunden: Wenn Sie echo $(ls -1 -tF | head -n 1) verwenden, kann der Datei Globing-Mechanismus zu zusätzlichen Übereinstimmungen führen.

So würde echo "$(ls -1 -tF | head -n 1)" dies vermeiden.

Wenn das Ergebnis eine ausführbare Datei ist, enthält es am Ende ein *.

Ich versuchte, die warum -F in einem Kommentar zu veröffentlichen, aber jetzt habe ich beschlossen, es setzen hier:

ich die folgenden Zeilen zu meinem .bashrc hinzugefügt, um eine Verknüpfung zu haben zuletzt geändert werden aufgelisteten Dateien oder Verzeichnisse:

function L { 
    myvar=$1; h=${myvar:="1"}; 
    echo "last ${h} modified file(s):"; 
    export L=$(ls -1 -tF|fgrep -v/|head -n ${h}| sed 's/\(\*\|=\|@\)$//g');  
    ls -l $L; 
} 
function LD { 
    myvar=$1; 
    h=${myvar:="1"}; 
    echo "last ${h} modified directories:"; 
    export LD=$(ls -1 -tF|fgrep/|head -n $h | sed 's/\(\*\|=\|@\)$//g'); ls -ld $LD; 
} 
alias ol='L; xdg-open $L' 
alias cdl='LD; cd $LD' 

So, jetzt kann ich L (oder L 5) die letzten (letzte 5) geänderten Dateien aufzulisten. Aber keine Verzeichnisse.

Und mit L; jmacs $ L Ich kann meinen Editor öffnen, um ihn zu bearbeiten. Traditionell habe ich meinen Alias ​​lt = 'ls -lrt' verwendet, aber dann muss ich den Namen erneut eingeben ...

Jetzt nach mkdir ... verwende ich cdl, um zu diesem Verzeichnis zu wechseln.

6

Das Problem tritt auf, weil Sie eine nicht quoted Subshell und -F Flag für ls Ausgänge Shell-Sonderzeichen an Dateinamen angehängt verwenden.

-F, --classify
append indicator (one of */=>@|) to entries

Ausführbare Dateien werden mit * angehängt.

Wenn Sie laufen

echo $(ls -1 -tF | head -n 1) 

dann

$(ls -1 -tF | head -n 1) 

einen Dateinamen zurückgeben, und wenn es passiert, auf eine andere Datei eine ausführbare Datei und auch sein das Präfix sein, dann wird es beide zurück.

Zum Beispiel, wenn Sie

test.sh 
test.sh.backup 

dann wird es

test.sh* 

zurückkehren, das sich bei hallten ERWEITERT

test.sh test.sh.backup 

die Subshell diese Expansion verhindert

Zitiert
echo "$(ls -1 -tF | head -n 1)" 

kehrt

test.sh* 
+1

großartige Erklärung .... mit geschweiften Klammern statt Klammern ist noch besser :) So: {ls -1 -tF | Kopf -n 1; } Keine Subshell wird erstellt – zee

+0

@zee Ohne das Echo könnten Sie einfach die Befehle ausführen, wie es ohne Klammern/Parenths ist – 123