Как получить переменную оболочки для значений, присутствующих в выводе psql? - PullRequest
0 голосов
/ 27 августа 2018

Вот краткое описание того, что я пытаюсь сделать:

Допустим, у меня в оболочке хранится CSV как переменная $. Это выглядит так:

account,index,quantity
100,AAPL,10
105,NFLX,25
110,TSLA,50
120,TWTR,45

Теперь я запрашиваю базу данных PSQL из оболочки следующим образом:

accounts=$(psql -d mydb -h mydb -f "SELECT account_num FROM accounts WHERE is_relevant")

Теперь у меня есть список учетных записей, которые хранятся в, казалось бы, неструктурированной переменной. Проще говоря, я хочу отфильтровать исходный CSV по значениям, указанным в запросе новых учетных записей.

1) Когда я вызываю echo для переменной, хранящей мой результат запроса, я получаю длинную строку вывода - просто объединенный список всех соответствующих учетных записей.

2) Когда я вызываю переменную head, каждый номер счета выдает ошибку:

head: cannot open '100' for reading: No such file or directory

Я вижу это и думаю: «shell не распознает эти записи как строки для печати, а скорее команды для запуска» - и я не уверен, как это исправить. Попытки использовать sed для размещения кавычек или запятых для разделения строк приводят к схожим ошибкам - либо в отношении отсутствующих файлов, либо несуществующих команд.

Хотя я подозреваю, что grep в конечном итоге правильный инструмент для этого - я хочу изложить это открыто. Как бы вы это сделали?

Редактировать: чтобы уточнить, учитывая мою исходную таблицу учетных записей, если запрос PSQL возвращает:

100
105
120

Я хочу отфильтровать исходную таблицу по этим значениям, чтобы получить:

account,index,quantity
100,AAPL,10
105,NFLX,25
120,TWTR,45

(Строка со счетом # 110 была отфильтрована.)

1 Ответ

0 голосов
/ 27 августа 2018

Вы можете попробовать это после запроса:

# Create a filtered_variable to store the filtered results
# and add the first line from the original variable (the CSV header)
filtered_variable=$(echo "$variable" | head -n 1)

# For each account in the accounts obtained in the query
for account in $accounts
do
    # Create a filtered_line variable to store the line where the account
    # appears in the CSV, or an empty line if the account is not in the CSV
    filtered_line=$(echo "$variable" | grep "^$account,")

    # If $filtered_line is not empty (the account is in the CSV) ...
    if [ ! -z "$filtered_line" ]
    then
        # ... add the line to the filtered_variable (filtered CSV)
        filtered_variable+=$'\n'"$filtered_line"
    fi
done

Теперь у вас есть отфильтрованная таблица в переменной filtered_variable. Если вы хотите его в оригинальном variable, просто выполните variable="$filtered_variable" после цикла.

Альтернативное решение

Вы также можете использовать egrep с регулярным выражением, которое включает все учетные записи, возвращенные в запросе. Например

echo "$variable" | egrep -e "^100,|^110,"

вернет

100,AAPL,10
110,TSLA,50

Это регулярное выражение ищет строки, начинающиеся с 100, или 110,. Я добавил ,, чтобы избежать ложных совпадений.

Итак, все, что вам нужно, это создать это регулярное выражение для всех учетных записей, возвращаемых в запросе. Это можно легко сделать с помощью sed:

filter=$(echo "^$accounts," | sed -e 's/ /,|^/g')

Теперь у вас есть фильтр в виде регулярного выражения в переменной filter, и все, что остается, это сделать egrep:

filtered_variable=$(echo "$variable" | egrep "$filter")

И снова у вас будут отфильтрованные учетные записи в вспомогательной переменной filtered_variable (не забудьте сначала добавить строку заголовка CSV).

...