В Bash, как прочитать файл и принять каждую строку в качестве инкрементной переменной?

У меня есть файл, подобный приведенному ниже: (list.txt)

127.0.0.1 us
127.0.0.2 uk
127.0.0.3 cn
127.0.0.4 fr
127.0.0.5 ru
127.0.0.6 bd
127.0.0.7 hk

Я хотел создать скрипт, который будет отображать пользователя в качестве элементов для выбора.

bash ping.sh
Which ip you want to test?

1) 127.0.0.1-us
2) 127.0.0.2-uk
3) 127.0.0.3-cn
4) 127.0.0.4-fr
5) 127.0.0.5-ru
6) 127.0.0.6-bd
7) 127.0.0.7-hk

Input: 6

ping -c 5 127.0.0.6

Этот список будет меняться при каждом изменении файла. Как я могу это сделать?

1
задан 26 March 2016 в 10:48

4 ответа

#!/bin/bash

PS3="Input: "

while read -r addr tld; do
  addrlist+=( "$addr" ) 
done < list.txt

echo "Which ip you want to test?"

select addr in "${addrlist[@]}"; do
  ping -c5 "$addr"
  break;
done
<час>

Примечание, что, если Ваш файл содержал просто сингл (адрес) поле, Вы могли бы иметь, использует удар mapfile встроенный (или его синоним readarray)

mapfile -t addrlist < list.txt

для заполнения массива без явного цикличного выполнения. Если Вы хотите точный написанный через дефис список, показанный в исходном вопросе затем, Вы могли бы сделать что-то как

mapfile -t addrlist < list.txt

echo "Which ip you want to test?"

select addr in "${addrlist[@]// /-}"; do
  ping -c5 "${addr%%-*}"
  break;
done

кроме кода, начинает становиться ужасным, по моему скромному мнению.

3
ответ дан 26 March 2016 в 20:48

Принятие этого bashВы имели в виду cli (терминальная) команда, чтобы сделать задание. Только коммуникационный раздел сделан python сама команда (конечно), сделана ping

Все в одном, в маленьком python сценарий:

#!/usr/bin/env python3
import subprocess
import sys

print("Which ip do you want to test?\n")
# create a numbered list of the lines
ips = list(enumerate(open(sys.argv[1]).read().splitlines()))
[print(str(i+1)+") "+ip) for i, ip in ips]
# run the command to ping
subprocess.call(["ping", "-c", "5", ips[int(input("\ninput: "))-1][1]])
  • Скопируйте сценарий в пустой файл, сохраните его как ping_ip.py
  • Выполните его с Вашим list.txt как аргумент:

    python3 /path/to/ping_ip.py /path/to/list.txt`
    

    enter image description here

Примечание:

Аргумент "5" (количество ping) находится в строке:

subprocess.call(["ping", "-c", "5", ips[int(input("\ninput: "))-1][1]])

но может очень хорошо быть изменен, чтобы использоваться в качестве аргумента при запущении скрипта. Если это было бы удобно, упомяните.

1
ответ дан 26 March 2016 в 20:48
  • 1
    @Ria отмечают, что это найдет все файлы, имя которых запускается с red_ в этом и любые подкаталоги , и оно повредится, если у Вас будет файл, названный red_foo, тот где текст после red_ isn' t число. – terdon♦ 28 June 2017 в 02:57
#!/bin/bash

IFS=\n'
select choice in $(cat list.txt; echo exit)
do
    # echo "$REPLY : $choice"
    if [[ $choice != "exit" ]]
    then
        echo "your choice was: "$choice
        # Run your program here
    else
        exit
    fi
done
2
ответ дан 26 March 2016 в 20:48
  • 1
    Я получаю ошибку, если я кавычка "red_*" в find выражение (как ожидалось - находят шарики, не должно быть заключено в кавычки), и я все еще добираюсь $var как количество последнего существующего файла, не следующего... – Zanna 27 June 2017 в 23:25

Вот то, что я придумал приблизительно за 5 - 10 минут просто проигрывания с AWK.

$ select entry in $(awk '{printf "%s-%s ",$1,$2}'  ips.txt) ; do                                      
> ip_address=$(awk -F '-' '{print $1}' <<< "$entry" )                                                                 
> echo "You selected "  "$ip_address"
> done
1) 127.0.0.1-us
2) 127.0.0.2-uk
3) 127.0.0.3-cn
4) 127.0.0.4-fr
5) 127.0.0.5-ru
6) 127.0.0.6-bd
7) 127.0.0.7-hk
#? 2
You selected  127.0.0.2

хитрая часть в Вашем вопросе просто обрабатывает строки текстового файла, который может использоваться соответственно select структура, потому что у Вас есть две записи на строку там. Ну, почему бы не превратить их в один объект и просто отправляют процесс для извлечения IP-адреса? Это точно, что я делаю в коде выше.

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

то, Что хорошо об этом подходе, - то, что это неуязвимо для недостающего местоположения, например, если бы в выборе № 2 uk отсутствовал, то мы все еще смогли бы читать 127.0.0.2

0
ответ дан 26 March 2016 в 20:48
  • 1
    Ваш NUM=$(echo $f| cut -d _ -f2) перестанет работать, если имя файла будет содержать новую строку (который является позором, так как остальная часть Вашего сценария устойчива). Просто используйте оболочку для удаления бита Вы don' t хотят: num=$(printf '%d' "${f##*_}"). Это также устраняет необходимость второго printf и использует имена переменной нижнего регистра, которые являются хорошей практикой в сценариях оболочки для предотвращения коллизии с переменными окружения. – terdon♦ 28 June 2017 в 03:01

Другие вопросы по тегам:

Похожие вопросы: