Также обратите внимание, что я добавил кавычки вокруг $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работает.
Мел Бойс
@MelBoyce: я добавил это к своему ответу. Благодарю.
ls - инструмент для интерактивного просмотра информации о файлах. Его вывод отформатирован для людей и будет вызывать ошибки в скриптах. Используйте шары или найдите вместо этого. Понять почему: mywiki.wooledge.org/ParsingLs
cinelli
@cinelli: это правда. Я просто отвечал на вопрос.
9
В конвейере все команды запускаются и выполняются одновременно, а не одна за другой. Так что вам нужно где-то хранить выходные данные.
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 >&2No match
fi
Чтобы использовать это правильно, чтобы удовлетворить цели вашего запроса:
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">&2fi
РЕДАКТИРОВАТЬ: после рассмотрения вопроса, я понял, что рассматриваемая lsкоманда ищет самый старый файл в каталоге. эту же функцию можно было бы переименовать oldestи [[ $file -ot $oldest ]] && oldest=$fileвместо этого добиться того же эффекта. извиняюсь за любую путаницу.
важно отметить, что вы абсолютно ни при каких обстоятельствах в человечестве не должны анализировать вывод ls. никогда.
Обратите внимание, что в отличие от lsподходов на основе, если есть символические ссылки, будет учитываться время модификации цели символических ссылок (добавьте -Lпараметр, lsчтобы получить то же поведение там).
Вместо сравнения $?Against 0, вы можете сделать это: if ls -rf $MY_DIR/FILE.*.xml ; then.
Кроме того, вы можете перенаправить вывод первой команды на /dev/null. ls -rf $MY_DIR/FILE.*.xml &> /dev/null, Таким образом, пользователь не увидит дополнительный вывод.
ls
не подведет.Ответы:
Попробуй это:
Переходя
xargs
к-r
флаг заставит его работать только ,basename
если считывает по меньшей мере один элемент из стандартного ввода (head -1
).head -1
будет работать, но вы не будете видеть или захватывать какие-либо выходные данные из него.Кроме того, если вы не хотите, чтобы пользователь видел какие-либо сообщения об ошибках
ls
, вы можете перенаправитьls
поток stderr в/dev/null
.Также обратите внимание, что я добавил кавычки вокруг
$MY_DIR
. Таким образом, команда не потерпит неудачу, если$MY_DIR
содержит пробелы.Если вы используете современную оболочку, такую как bash, вы должны использовать
$( )
оболочку захвата вместо обратных галочек. Вам также следует подумать об изменении стиля ваших переменных. Как правило, следует избегать использования имен переменных в верхнем регистре в сценариях. Этот стиль обычно зарезервирован для зарезервированных и переменных среды.источник
ls -rt GLOB 2>/dev/null | head -n1 | xargs -r basename
работает.В конвейере все команды запускаются и выполняются одновременно, а не одна за другой. Так что вам нужно где-то хранить выходные данные.
Обратите внимание, что предполагается, что имена файлов не содержат символов новой строки. Использование
xargs
также означало бы проблемы с пустыми символами, одинарными и двойными кавычками и обратной косой чертой. Если оставить переменные без кавычек, это будет означать проблемы с пробелами, символами табуляции и подстановочными символами. Забывание--
означало бы проблемы с именами файлов, начинающимися с-
.Чтобы получить базовое имя самого старого файла
zsh
без каких-либо ограничений на символы (также устраняется проблема ограниченного размера аргументов команды):Если совпадений нет, эта команда завершится ошибкой и прервет сценарий. Вы также можете сделать:
В этом случае
first_file_name
массив будет содержать 1 элемент, если есть совпадение, или 0, если нет. Затем вы можете сделать:источник
Найти последний измененный файл в каталоге:
Использование:
latest [directory/path/ [.extension]]
Вместо вызова
basename
, используйте расширение параметра.В каталоге с таким содержанием:
Содержимое переменной base_fn будет:
newest
Чтобы использовать это правильно, чтобы удовлетворить цели вашего запроса:
РЕДАКТИРОВАТЬ: после рассмотрения вопроса, я понял, что рассматриваемая
ls
команда ищет самый старый файл в каталоге. эту же функцию можно было бы переименоватьoldest
и[[ $file -ot $oldest ]] && oldest=$file
вместо этого добиться того же эффекта. извиняюсь за любую путаницу.важно отметить, что вы абсолютно ни при каких обстоятельствах в человечестве не должны анализировать вывод ls. никогда.
источник
ls
подходов на основе, если есть символические ссылки, будет учитываться время модификации цели символических ссылок (добавьте-L
параметр,ls
чтобы получить то же поведение там).Я думаю, что лучший вариант здесь:
если файла нет, то код возврата ls равен 2, но если он найдет какой-то файл, то будет 0.
источник
$?
Against0
, вы можете сделать это:if ls -rf $MY_DIR/FILE.*.xml ; then
./dev/null
.ls -rf $MY_DIR/FILE.*.xml &> /dev/null
, Таким образом, пользователь не увидит дополнительный вывод.