Como obter a sua Latitude e Longitude no Terminal para usar no Redshift

Estou usando o Openbox no Arch, e com isso precisei instalar o Redshift, para ter aquele filtro de luz azul. Porém, por algum motivo, a localização automática dele pelo geoclue não funcionou e como o Redshift tem uma forma manual, decidi por usar ele.

Mas, me veio uma questão: Será que é possível obter a localização para usar no Redshift de outra forma?

Uma solução

Pesquisando um pouco, encontrei uma solução que envolvia o curl e o site ipinfo.io. No site, tem um arquivo que exibe a localização e outros dados do seu IP e usando o curldá pra exibir essas informações no terminal. E com um…

curl -s ipinfo.io

Teremos uma saída nesse modelo:

{
  "ip": "<SEU IP AQUI>",
  "hostname": "<SEU PROVEDOR DE INTERNET AQUI>",
  "city": "<SUA CIDADE AQUI>",
  "region": "<SUA REGIÃO/ESTADO AQUI>",
  "country": "PAÍS",
  "loc": "<LATITUDE>,<LONGITUDE>",
  "org": "<NOME DO PROVEDOR AQUI>",
  "postal": "<CÓDIGO POSTAL>",
  "timezone": "<FUSO HORÁRIO AQUI>",
  "readme": "https://ipinfo.io/missingauth"
}

Mas queremos apenas a informação da Latitude e Longitude. Com isso, vamos para outro comando:

curl -s https://ipinfo.io | grep "loc"

Com a adição do | grep “loc”, filtraremos a linha com a Latitude e Longitude, que ficará mais ou menos assim:

"loc": "<LATITUDE>,<LONGITUDE>",

Mas isso não é o suficiente. Precisamos refinar um pouco mais a saída. Nesse “trenzinho”, podemos adicionar mais um comando:

curl -s https://ipinfo.io | grep "loc" | awk -F ‘"’ ‘{ print $4 }’

O | awk -F ‘"’ ‘{ print $4 }’ irá cortar tudo o que está antes das ". Com esse comando, a saída ficará mais ou menos assim:

<LATITUDE>,<LONGITUDE>

Para alguns casos, isso é o suficiente. Mas e se quisermos extrair somente a Latitude ou a Longitude?

Aqui entra mais um awk, nesse caso, o | awk -F ‘,’ ‘{ print $1}’) para extrair somente o que está antes da vírgula (ou seja, a Latitude) ou | awk -F ‘,’ ‘{ print $2}’) para extrair somente o que está depois da vírgula (ou seja, a Longitude).

Aplicando isso num Script

Dada essa explicação, para aplicar isso num Script, ficaria mais ou menos assim:

#! /bin/bash

loc=$(curl -s https://ipinfo.io | grep "loc" | awk -F '"' '{ print $4 }')
	
lat=$(echo $loc | awk -F ',' '{ print $1}')
lon=$(echo $loc | awk -F ',' '{ print $2}')

redshift -l $lat:$lon

Melhorando um pouco mais

Mas dá pra melhorar isso um pouco mais: Como verificar a conexão com a Internet? Com outro curl, nesse caso, o curl -Is ``https://ipinfo.io/json, em que o I diz para o curl exibir o cabeçalho de resposta HTTP. O que dá esse calhamaço aqui:

HTTP/2 200
access-control-allow-origin: *
x-content-type-options: nosniff
content-type: application/json; charset=utf-8
content-length: 326
date: Thu, 31 Jul 2025 01:41:48 GMT
via: 1.1 google
strict-transport-security: max-age=2592000; includeSubDomains
alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000

Mas, só precisamos da primeira linha (HTTP/2 200). Com isso, vem um | head -n 1, que filtra somente a primeira linha dessa saída. O que deixa esse comando mais ou menos assim:

curl -Is  https://ipinfo.io/json | head -n 1

E a saída desse comando, quando não tem a conexão com a internet é vazia, então dá pra juntar com um if -z, e assim tratar o que fazer quando não ter a conexão com a Internet.

Aplicando a melhoria num Script

O Script completo, ficou assim, com essa melhoria da conexão com a Internet ficou assim:

#! /bin/bash

if [ -z "$(curl -Is  https://ipinfo.io/json | head -n 1)" ]; then ## Baixando um arquivo para detectar a conexão da Internet
	echo "## ERROR: Connection not found!"
	echo "## Using Latitude and Longitude 0:0"
	
	## Se não houver a conexão com a Internet, usar a Latitude e Longitude 0:0
	lat=0
	lon=0
	
else
	echo "## Connection OK"
	echo "## Detecting Latitude and Longitude..."
	
	# Se houver conexão com a Internet, baixar um arquivo do ipinfo.io, com as informações do IP, filtrar o campo localização e com isso, extrair a Latitude e Longitude.
	loc=$(curl -s https://ipinfo.io/json | grep "loc" | awk -F '"' '{ print $4 }')
	
	lat=$(echo $loc | awk -F ',' '{ print $1}')
	lon=$(echo $loc | awk -F ',' '{ print $2}')
	
	echo -e "\n## Latitude: $lat"
	echo "## Longitude: $lon"
fi


echo -e "\n##Starting Redshift..."
redshift -l $lat:$lon

4 curtidas

Uma alternativa para você usar, que eu já usei, é o site Geocode.xyz…
De uma olhada na API deles… Só tem o incomodo de limitar o acesso a API de uma consulta por segundo (sem API key), mas se não for fazer muitas requisições por segundo, é uma boa alternativa.

3 curtidas

Quando eu precisava dessa informação pra colocar no sistema de controle de armas do exército eu usava o Google Maps.

3 curtidas

Gostei dele, também parece funcionar muito bem. Acho que poderei usar ele como alternativa.

1 curtida

Antes o Google Maps permitia o uso sem APIkey, hoje só se você tiver uma APIkey do Google Cloud Developer e inscrito no projeto… Ou via web scraping no Google Maps para ser sem APIkey.

2 curtidas

No meu caso, eu simplesmente entrava no Google Maps, colocava o endereço e copiava as coordenadas. Não precisava ser nada automatizado.

2 curtidas

Eu sempre cliquei mais ou menos na minha localização usando o Google Maps ou OSM hehe, nunca pensei em automatizar isso.

4 curtidas

Minhas ideias para abreviar esse script:

#!/bin/sh

if loc=$(curl -sf https://ipinfo.io/json); then
	IFS=, read lat lon <<EOF
$(printf '%s' "$loc" | awk -F'"' '/loc/ { print $4 }')
EOF
else
	echo 'Conexão ao ipinfo.io falhou, usando coordenadas padrão...' >&2
	lat=0
	lon=0
fi

set -x
exec redshift -l "$lat:$lon" "$@"
  • O curl possui a opção -f, que faz ele dar um status de saída de falha para o if/&& não só se a conexão falhar, mas também se a resposta HTTP não for 200/OK. Junto com o fato de que uma linha no estilo VAR=$(comando) traz o mesmo status de saída do comando dentro do $(), isso nos poupa de termos que chamá-lo só para analisar os cabeçalhos com head -n1.
  • O recurso de “encontrar padrões” do awk (/expressao-regular/ { script } em vez de só { script }) poupa o grep "loc".
  • O comando read pode ser usado não só para ler o que o usuário digita, mas também para separar strings (inserindo-as como heredocs — usando <<EOF no fim de uma linha, botando o texto, e uma linha só com EOF para finalizar, como no exemplo — ou herestrings comando <<< "texto") em mais de uma variável – cada argumento do read é o nome de uma variável. Por padrão ele separa nos espaços, mas podemos definir os caracteres que vão servir de delimitador com o prefixo IFS=[caracteres], no caso, a vírgula. Assim poupamos os dois awk -F , aqui.
  • O >&2 no echo faz a mensagem de erro ir para o terminal (ou seja qual for o local dedicado para a análise de erros) em vez da saída padrão. Para um script pessoal que imediatamente executa outro programa, faz pouca diferença, mas é uma boa prática, especialment para scripts que gerem dados para pipelines.
  • Prefixei o redshift com exec, que garante que o shell vai encerrar quando o comando executar, e coloquei "$@" no final, que repassa quaisquer argumentos ou opções que o script recebeu para o Redshift, removendo a necessidade de fazer cópias para colocar opções a mais.
  • É uma boa prática manter variáveis dentro de aspas ("$lat:$loc" em vez de só $lat:$loc) devido ao wordsplitting.

Por questão de gosto, eu coloquei menos mensagens informativas. Em vez disso, coloquei set -x, que faz o shell exibir cada linha de código executada, antes de invocar o Redshift; daí a linha de comando vai ter a latitude e longitude.

3 curtidas

Adorei as melhorias e realmente simplificou muito o Script. Não sabia que o read e o EOF poderiam ser usados dessa forma.

Também sou novo no uso do curl e até tinha usado o awkantes, e aqui eu usei ele como eu tinha usado em outros Scripts.

2 curtidas