Observe também que adicionei aspas $MY_DIR. Dessa forma, o comando não falhará se $MY_DIRcontiver espaços.
Se você estiver usando um shell moderno como o bash, use um $( )shell de captura em vez de backticks. Você também deve mudar o estilo de suas variáveis. Geralmente, você deve evitar o uso de nomes de variáveis com todas as letras maiúsculas nos scripts. Esse estilo geralmente é reservado para variáveis reservadas e ambientais.
input_file=$(ls -rt "$my_dir"/FILE.*.xml 2>/dev/null | head -1| xargs -r basename)
Na verdade: ls -rt GLOB 2>/dev/null | head -n1 | xargs -r basenamefunciona.
Mel Boyce
@MelBoyce: Adicionei isso à minha resposta. Obrigado.
ls é uma ferramenta para analisar interativamente as informações do arquivo. Sua saída é formatada para humanos e causará erros nos scripts. Use globs ou encontre. Entenda o porquê: mywiki.wooledge.org/ParsingLs
Cinelli
@cinelli: Isso é verdade. Eu estava apenas respondendo a pergunta.
9
Em uma linha de tubulação, todos os comandos são iniciados e executados simultaneamente, não um após o outro. Então você precisa armazenar a saída em algum lugar.
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
Observe que ele assume que os nomes dos arquivos não contêm caracteres de nova linha. O uso xargstambém significaria problemas com caracteres em branco, aspas simples e duplas e barras invertidas. Deixar as variáveis sem aspas significaria problemas com caracteres de espaço, tabulação e curinga. Esquecer --significaria problemas com nomes de arquivos começando com -.
Para obter o nome de base do arquivo mais antigo zshsem nenhuma dessas restrições de caracteres (também evita o problema do tamanho limitado dos argumentos de um comando):
first_file_name=($MY_DIR/FILE.*.xml(Om[1]:t))
Se não houver correspondência, esse comando falhará e abortará o script. Você também pode fazer:
first_file_name=($MY_DIR/FILE.*.xml(NOm[1]:t))
Nesse caso, o first_file_name matriz conterá 1 elemento, se houver uma correspondência, ou 0, se não houver. Você pode então fazer:
if(($#first_file_name)); then
printf 'Match: %s\n' $first_file_name
else
echo >&2No match
fi
Para usá-lo corretamente para servir ao propósito de sua solicitação:
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
EDIT: após a revisão da questão, percebi que o lscomando em questão está procurando o arquivo mais antigo em um diretório. essa mesma função pode ser renomeada paraoldest e ter[[ $file -ot $oldest ]] && oldest=$file o mesmo efeito. desculpas por qualquer confusão.
o importante a ser observado é que você absolutamente, sob nenhuma circunstância jamais na humanidade, deve analisar a produção de ls. Nunca.
Observe que, ao contrário das lsabordagens baseadas em, se houver links simbólicos, o tempo de modificação do destino dos links simbólicos será considerado (adicione a -Lopção lspara obter o mesmo comportamento).
Em vez de comparar $?contra 0, você pode fazer isso: if ls -rf $MY_DIR/FILE.*.xml ; then.
Além disso, você pode redirecionar a saída do primeiro comando para /dev/null. ls -rf $MY_DIR/FILE.*.xml &> /dev/null. Dessa forma, o usuário não verá a saída extra.
ls
não falhará.Respostas:
Tente o seguinte:
Passar
xargs
o-r
sinalizador fará com que ele seja executado apenasbasename
se ler pelo menos um item da entrada padrão (head -1
).head -1
será executado, mas você não verá nem capturará nenhuma saída dele.Além disso, se você não quiser que o usuário veja nenhuma saída de erro
ls
, poderá redirecionarls
o fluxo stderr para/dev/null
.Observe também que adicionei aspas
$MY_DIR
. Dessa forma, o comando não falhará se$MY_DIR
contiver espaços.Se você estiver usando um shell moderno como o bash, use um
$( )
shell de captura em vez de backticks. Você também deve mudar o estilo de suas variáveis. Geralmente, você deve evitar o uso de nomes de variáveis com todas as letras maiúsculas nos scripts. Esse estilo geralmente é reservado para variáveis reservadas e ambientais.fonte
ls -rt GLOB 2>/dev/null | head -n1 | xargs -r basename
funciona.Em uma linha de tubulação, todos os comandos são iniciados e executados simultaneamente, não um após o outro. Então você precisa armazenar a saída em algum lugar.
Observe que ele assume que os nomes dos arquivos não contêm caracteres de nova linha. O uso
xargs
também significaria problemas com caracteres em branco, aspas simples e duplas e barras invertidas. Deixar as variáveis sem aspas significaria problemas com caracteres de espaço, tabulação e curinga. Esquecer--
significaria problemas com nomes de arquivos começando com-
.Para obter o nome de base do arquivo mais antigo
zsh
sem nenhuma dessas restrições de caracteres (também evita o problema do tamanho limitado dos argumentos de um comando):Se não houver correspondência, esse comando falhará e abortará o script. Você também pode fazer:
Nesse caso, o
first_file_name
matriz conterá 1 elemento, se houver uma correspondência, ou 0, se não houver. Você pode então fazer:fonte
Encontre o arquivo modificado mais recente em um diretório:
Uso:
latest [directory/path/ [.extension]]
Em vez de chamar
basename
, use expansão de parâmetro.Em um diretório com este conteúdo:
O conteúdo da variável base_fn seria:
newest
Para usá-lo corretamente para servir ao propósito de sua solicitação:
EDIT: após a revisão da questão, percebi que o
ls
comando em questão está procurando o arquivo mais antigo em um diretório. essa mesma função pode ser renomeada paraoldest
e ter[[ $file -ot $oldest ]] && oldest=$file
o mesmo efeito. desculpas por qualquer confusão.o importante a ser observado é que você absolutamente, sob nenhuma circunstância jamais na humanidade, deve analisar a produção de ls. Nunca.
fonte
ls
abordagens baseadas em, se houver links simbólicos, o tempo de modificação do destino dos links simbólicos será considerado (adicione a-L
opçãols
para obter o mesmo comportamento).Eu acho que a melhor opção aqui é:
se não houver arquivo, o código de retorno de ls será 2, mas se encontrar algum arquivo será 0.
fonte
$?
contra0
, você pode fazer isso:if ls -rf $MY_DIR/FILE.*.xml ; then
./dev/null
.ls -rf $MY_DIR/FILE.*.xml &> /dev/null
. Dessa forma, o usuário não verá a saída extra.