INPUT_FILE=`ls -rt $MY_DIR/FILE.*.xml | head -1 | xargs basename`
Chciałem wykonać drugie polecenie ( head -1
) tylko wtedy, gdy pierwsze polecenie zakończy się powodzeniem. Jak poprawić to polecenie?
INPUT_FILE=`ls -rt $MY_DIR/FILE.*.xml | head -1 | xargs basename`
Chciałem wykonać drugie polecenie ( head -1
) tylko wtedy, gdy pierwsze polecenie zakończy się powodzeniem. Jak poprawić to polecenie?
Odpowiedzi:
Spróbuj tego:
INPUT_FILE=`ls -rt "$MY_DIR"/FILE.*.xml | head -1 | xargs -r basename`
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
.
INPUT_FILE=`ls -rt "$MY_DIR"/FILE.*.xml 2> /dev/null | head -1 | xargs -r basename`
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.
input_file=$(ls -rt "$my_dir"/FILE.*.xml 2> /dev/null | head -1 | xargs -r basename)
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.
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 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):
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_name
tablica 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_name
else
echo >&2 No match
fi
Znajdź najnowszy zmodyfikowany plik w katalogu:
latest() {
local file path=${1:-.} ext=${2-} latest
for file in "${path%/}"/*"$ext"; do
[[ $file -nt $latest ]] && latest=$file
done
[[ $latest ]] && printf '%s\n' "$latest"
}
Stosowanie: latest [directory/path/ [.extension]]
Zamiast wołać do basename
, użyj rozszerzenia parametrów.
in_file=$(latest in/my/dir .xml)
base_fn=${in_file##*/} base_fn=${base_fn%.*}
W katalogu z tymi treściami:
foo.xml bar.xml baz.xml newest.xml
Zawartość zmiennej base_fn będzie wynosić: newest
Aby właściwie to wykorzystać, aby zrealizować cel żądania:
check_dir=/path/to/check
check_ext=.xml
if 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" >&2
fi
EDYCJA: po przejrzeniu pytania uświadomiłem sobie, że to ls
polecenie szuka najstarszego pliku w katalogu. Ta sama funkcja może być zmieniona na oldest
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.
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:
ls -rf $MY_DIR/FILE.*.xml
if [ $? -eq 0 ]; then
INPUT_FILE=`ls -rt $MY_DIR/FILE.*.xml|head -1|xargs basename `
else
echo "Error!"
fi
jeśli nie ma pliku, kod powrotu ls to 2, ale jeśli znajdzie jakiś plik, będzie miał wartość 0.
ls
nie zawiedzie.