Zauważ też, że dodałem znaki cudzysłowu $MY_DIR. W ten sposób polecenie nie zawiedzie, jeśli $MY_DIRzawiera spacje.
Jeśli używasz nowoczesnej powłoki, takiej jak bash, powinieneś użyć $( )powłoki przechwytującej zamiast backkicks. Powinieneś także rozważyć zmianę stylu swoich zmiennych. Zasadniczo należy unikać używania w skryptach nazw zmiennych składających się z wielkich liter. Ten styl jest ogólnie zarezerwowany dla zmiennych zarezerwowanych i zmiennych środowiskowych.
input_file=$(ls -rt "$my_dir"/FILE.*.xml 2>/dev/null | head -1| xargs -r basename)
Właściwie: ls -rt GLOB 2>/dev/null | head -n1 | xargs -r basenamedziała.
Mel Boyce,
@MelBoyce: Dodałem to do mojej odpowiedzi. Dzięki.
ls to narzędzie do interaktywnego przeglądania informacji o plikach. Jego dane wyjściowe są sformatowane dla ludzi i będą powodować błędy w skryptach. Zamiast tego użyj globów lub znajdź. Dowiedz się,
cinelli
@cinelli: To prawda. Właśnie odpowiadałem na pytanie.
9
W linii potoku wszystkie polecenia są uruchamiane i uruchamiane jednocześnie, nie jedna po drugiej. Musisz gdzieś przechowywać dane wyjściowe.
if ls_output=$(ls -rtd --"$MY_DIR"/FILE.*.xml);then
first_file=$(printf '%s\n'"$ls_output"| head -n 1)
first_file_name=$(basename --"$first_file")fi
Zauważ, że zakłada, że nazwy plików nie zawierają znaków nowej linii. Używanie xargsoznaczałoby również problemy z pustymi znakami, pojedynczymi i podwójnymi cudzysłowami oraz odwrotnymi ukośnikami. Pozostawienie zmiennych bez cudzysłowu oznaczałoby problemy ze spacjami, tabulatorami i znakami wieloznacznymi. Zapominanie --oznaczałoby problemy z nazwami plików zaczynającymi się od -.
Aby uzyskać nazwę bazową najstarszego pliku zshbez żadnych ograniczeń dotyczących znaków (pozwala również uniknąć problemu ograniczonej wielkości argumentów polecenia):
first_file_name=($MY_DIR/FILE.*.xml(Om[1]:t))
Jeśli nie ma dopasowania, to polecenie zakończy się niepowodzeniem i przerwie skrypt. Możesz także:
first_file_name=($MY_DIR/FILE.*.xml(NOm[1]:t))
W takim przypadku first_file_nametablica będzie zawierać 1 element, jeśli występuje dopasowanie, lub 0, jeśli nie. Następnie możesz wykonać:
if(($#first_file_name)); then
printf 'Match: %s\n' $first_file_nameelse
echo >&2No matchfi
Aby właściwie to wykorzystać, aby zrealizować cel żądania:
check_dir=/path/to/check
check_ext=.xmlif in_file=$(latest "$check_dir""$check_ext");then
base_fn=${in_file##*/} base_fn=${base_fn%.*}else
printf '%s\n'"No file found in $check_dir">&2fi
EDYCJA: po przejrzeniu pytania uświadomiłem sobie, że to lspolecenie szuka najstarszego pliku w katalogu. Ta sama funkcja może być zmieniona na oldesti mieć [[ $file -ot $oldest ]] && oldest=$filezamiast osiągnąć ten sam efekt. przepraszam za zamieszanie.
ważną rzeczą do zapamiętania jest to, że absolutnie, pod żadnym pozorem w ludzkości, nie powinieneś analizować wyników ls. nigdy.
Zauważ, że w przeciwieństwie do lsmetod opartych na bazach, jeśli istnieją dowiązania symboliczne, rozważony zostanie czas modyfikacji celu dowiązań symbolicznych (dodaj -Lopcję lsuzyskania takiego samego zachowania).
Zamiast porównywać $?Against 0, można to zrobić: if ls -rf $MY_DIR/FILE.*.xml ; then.
Możesz także przekierować wyjście pierwszego polecenia /dev/null. ls -rf $MY_DIR/FILE.*.xml &> /dev/null. W ten sposób użytkownik nie zobaczy dodatkowych danych wyjściowych.
ls
nie zawiedzie.Odpowiedzi:
Spróbuj tego:
Przechodząc
xargs
do-r
flagi spowoduje to tylko uruchomićbasename
jeśli czyta przynajmniej jeden element ze standardowego wejścia (head -1
).head -1
będzie działać, ale nie zobaczysz ani nie wychwycisz z niego żadnych danych wyjściowych.Ponadto, jeśli nie chcesz, aby użytkownik widział wynik wyjściowy błędu
ls
, możesz przekierowaćls
strumień stderr do/dev/null
.Zauważ też, że dodałem znaki cudzysłowu
$MY_DIR
. W ten sposób polecenie nie zawiedzie, jeśli$MY_DIR
zawiera spacje.Jeśli używasz nowoczesnej powłoki, takiej jak bash, powinieneś użyć
$( )
powłoki przechwytującej zamiast backkicks. Powinieneś także rozważyć zmianę stylu swoich zmiennych. Zasadniczo należy unikać używania w skryptach nazw zmiennych składających się z wielkich liter. Ten styl jest ogólnie zarezerwowany dla zmiennych zarezerwowanych i zmiennych środowiskowych.źródło
ls -rt GLOB 2>/dev/null | head -n1 | xargs -r basename
działa.W linii potoku wszystkie polecenia są uruchamiane i uruchamiane jednocześnie, nie jedna po drugiej. Musisz gdzieś przechowywać dane wyjściowe.
Zauważ, że zakłada, że nazwy plików nie zawierają znaków nowej linii. Używanie
xargs
oznaczałoby również problemy z pustymi znakami, pojedynczymi i podwójnymi cudzysłowami oraz odwrotnymi ukośnikami. Pozostawienie zmiennych bez cudzysłowu oznaczałoby problemy ze spacjami, tabulatorami i znakami wieloznacznymi. Zapominanie--
oznaczałoby problemy z nazwami plików zaczynającymi się od-
.Aby uzyskać nazwę bazową najstarszego pliku
zsh
bez żadnych ograniczeń dotyczących znaków (pozwala również uniknąć problemu ograniczonej wielkości argumentów polecenia):Jeśli nie ma dopasowania, to polecenie zakończy się niepowodzeniem i przerwie skrypt. Możesz także:
W takim przypadku
first_file_name
tablica będzie zawierać 1 element, jeśli występuje dopasowanie, lub 0, jeśli nie. Następnie możesz wykonać:źródło
Znajdź najnowszy zmodyfikowany plik w katalogu:
Stosowanie:
latest [directory/path/ [.extension]]
Zamiast wołać do
basename
, użyj rozszerzenia parametrów.W katalogu z tymi treściami:
Zawartość zmiennej base_fn będzie wynosić:
newest
Aby właściwie to wykorzystać, aby zrealizować cel żądania:
EDYCJA: po przejrzeniu pytania uświadomiłem sobie, że to
ls
polecenie szuka najstarszego pliku w katalogu. Ta sama funkcja może być zmieniona naoldest
i mieć[[ $file -ot $oldest ]] && oldest=$file
zamiast osiągnąć ten sam efekt. przepraszam za zamieszanie.ważną rzeczą do zapamiętania jest to, że absolutnie, pod żadnym pozorem w ludzkości, nie powinieneś analizować wyników ls. nigdy.
źródło
ls
metod opartych na bazach, jeśli istnieją dowiązania symboliczne, rozważony zostanie czas modyfikacji celu dowiązań symbolicznych (dodaj-L
opcjęls
uzyskania takiego samego zachowania).Myślę, że najlepszą opcją jest tutaj:
jeśli nie ma pliku, kod powrotu ls to 2, ale jeśli znajdzie jakiś plik, będzie miał wartość 0.
źródło
$?
Against0
, można to zrobić:if ls -rf $MY_DIR/FILE.*.xml ; then
./dev/null
.ls -rf $MY_DIR/FILE.*.xml &> /dev/null
. W ten sposób użytkownik nie zobaczy dodatkowych danych wyjściowych.