INPUT_FILE=`ls -rt $MY_DIR/FILE.*.xml | head -1 | xargs basename`
Я хотел выполнить вторую команду ( head -1
), только если первая команда успешна. Как мне улучшить эту команду?
INPUT_FILE=`ls -rt $MY_DIR/FILE.*.xml | head -1 | xargs basename`
Я хотел выполнить вторую команду ( head -1
), только если первая команда успешна. Как мне улучшить эту команду?
Ответы:
Попробуй это:
INPUT_FILE=`ls -rt "$MY_DIR"/FILE.*.xml | head -1 | xargs -r basename`
Переходя xargs
к -r
флаг заставит его работать только , basename
если считывает по меньшей мере один элемент из стандартного ввода ( head -1
).
head -1
будет работать, но вы не будете видеть или захватывать какие-либо выходные данные из него.
Кроме того, если вы не хотите, чтобы пользователь видел какие-либо сообщения об ошибках ls
, вы можете перенаправить ls
поток stderr в /dev/null
.
INPUT_FILE=`ls -rt "$MY_DIR"/FILE.*.xml 2> /dev/null | head -1 | xargs -r basename`
Также обратите внимание, что я добавил кавычки вокруг $MY_DIR
. Таким образом, команда не потерпит неудачу, если $MY_DIR
содержит пробелы.
Если вы используете современную оболочку, такую как bash, вы должны использовать $( )
оболочку захвата вместо обратных галочек. Вам также следует подумать об изменении стиля ваших переменных. Как правило, следует избегать использования имен переменных в верхнем регистре в сценариях. Этот стиль обычно зарезервирован для зарезервированных и переменных среды.
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
работает.
В конвейере все команды запускаются и выполняются одновременно, а не одна за другой. Так что вам нужно где-то хранить выходные данные.
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
Обратите внимание, что предполагается, что имена файлов не содержат символов новой строки. Использование xargs
также означало бы проблемы с пустыми символами, одинарными и двойными кавычками и обратной косой чертой. Если оставить переменные без кавычек, это будет означать проблемы с пробелами, символами табуляции и подстановочными символами. Забывание --
означало бы проблемы с именами файлов, начинающимися с -
.
Чтобы получить базовое имя самого старого файла zsh
без каких-либо ограничений на символы (также устраняется проблема ограниченного размера аргументов команды):
first_file_name=($MY_DIR/FILE.*.xml(Om[1]:t))
Если совпадений нет, эта команда завершится ошибкой и прервет сценарий. Вы также можете сделать:
first_file_name=($MY_DIR/FILE.*.xml(NOm[1]:t))
В этом случае first_file_name
массив будет содержать 1 элемент, если есть совпадение, или 0, если нет. Затем вы можете сделать:
if (($#first_file_name)); then
printf 'Match: %s\n' $first_file_name
else
echo >&2 No match
fi
Найти последний измененный файл в каталоге:
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"
}
Использование: latest [directory/path/ [.extension]]
Вместо вызова basename
, используйте расширение параметра.
in_file=$(latest in/my/dir .xml)
base_fn=${in_file##*/} base_fn=${base_fn%.*}
В каталоге с таким содержанием:
foo.xml bar.xml baz.xml newest.xml
Содержимое переменной base_fn будет: newest
Чтобы использовать это правильно, чтобы удовлетворить цели вашего запроса:
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
РЕДАКТИРОВАТЬ: после рассмотрения вопроса, я понял, что рассматриваемая ls
команда ищет самый старый файл в каталоге. эту же функцию можно было бы переименовать oldest
и [[ $file -ot $oldest ]] && oldest=$file
вместо этого добиться того же эффекта. извиняюсь за любую путаницу.
важно отметить, что вы абсолютно ни при каких обстоятельствах в человечестве не должны анализировать вывод ls. никогда.
ls
подходов на основе, если есть символические ссылки, будет учитываться время модификации цели символических ссылок (добавьте -L
параметр, ls
чтобы получить то же поведение там).
Я думаю, что лучший вариант здесь:
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
если файла нет, то код возврата ls равен 2, но если он найдет какой-то файл, то будет 0.
ls
не подведет.