Canaliza a saída de um comando se ele for bem-sucedido

11
INPUT_FILE='ls -rt $MY_DIR/FILE.*.xml | head -1 | xargs basename'

Eu queria executar o segundo comando ( head -1 ) somente se o primeiro comando for bem-sucedido. Como eu melhoro este comando?

    
por Govind Kailas 23.07.2013 / 15:08

4 respostas

8

Tente isto:

INPUT_FILE='ls -rt "$MY_DIR"/FILE.*.xml | head -1 | xargs -r basename'

Passar xargs o -r flag fará com que ele execute somente basename se as leituras de 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 qualquer saída de erro de ls , poderá redirecionar o fluxo stderr de ls para /dev/null .

INPUT_FILE='ls -rt "$MY_DIR"/FILE.*.xml 2> /dev/null | head -1 | xargs -r basename'

Observe também que adicionei aspas em torno de $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, você deve usar um shell de captura $( ) em vez de backticks. Você também deve considerar mudar o estilo de suas variáveis. Você geralmente deve evitar usar nomes de variáveis em maiúsculas em 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)
    
por 23.07.2013 / 15:26
7

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 os nomes de arquivos não contêm caracteres de nova linha. Usar 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 espaço, tabulação e caracteres curinga. Esquecer -- significaria problemas com nomes de arquivos que começam com - .

Para obter o nome de base do arquivo mais antigo com zsh sem nenhuma dessas restrições em caracteres (também evita o problema do tamanho limitado de argumentos para 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, a matriz first_file_name conterá 1 elemento se houver uma correspondência ou 0, se não. Você pode então fazer:

 if (($#first_file_name)); then
    printf 'Match: %s\n' $first_file_name
 else
    echo >&2 No match
 fi
    
por 23.07.2013 / 15:53
4

Encontre o arquivo modificado mais recente em um diretório:

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"
}

Uso: latest [directory/path/ [.extension]]

Em vez de chamar basename , use a expansão de parâmetros.

in_file=$(latest in/my/dir .xml)
base_fn=${in_file##*/} base_fn=${base_fn%.*}

Em um diretório com este conteúdo:

foo.xml bar.xml baz.xml newest.xml

O conteúdo da variável base_fn seria: newest

Para usar isso corretamente para atender ao objetivo da 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" >&2
fi

EDIT: após a revisão da pergunta, percebi que o comando ls em questão está procurando o arquivo mais antigo em um diretório. essa mesma função pode ser renomeada para oldest e ter [[ $file -ot $oldest ]] && oldest=$file para obter o mesmo efeito. desculpas por qualquer confusão.

O importante a notar é que você absolutamente, nunca em nenhuma circunstância, nunca na humanidade, não deve analisar a saída de ls. nunca.

    
por 23.07.2013 / 16:41
0

Acho que a melhor opção aqui é:

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

se não houver arquivo, o código de retorno de ls é 2, mas se encontrar algum arquivo, será 0.

    
por 23.07.2013 / 15:17