строка bash для массива с пробелами и дополнительными разделителями - PullRequest
4 голосов
/ 30 декабря 2011

Я пытаюсь создать массивы из строк, которые имеют разделитель ("|") в качестве разделителей и содержат пробелы.Некоторое время я оглядывался по сторонам, и благодаря источникам, таким как , я узнал, как разделить строку на разделителе в Bash? , Разделить строку на массив икуча больше.Я близко, но это не совсем работает.Две основные проблемы заключаются в том, что в строках есть пробелы, есть начальный и конечный разделители, а некоторые поля не заполнены.Кроме того, вместо того, чтобы просто отображать значения, мне нужно присвоить их переменным.Вот формат исходных данных:

|username|full name|phone1|phone2|date added|servers|comments|

Пример:

|jdoe | John Doe| 555-1212 | |1/1/11 |  workstation1, server1 | added by me |

Вот что мне нужно:

Username: jdoe
Fullname: John Doe
Phone1: 555-1212
Phone2: 
Date_added: 1/1/11
Servers: workstation1, server1
Comments: guest account

Редактировать: я использую sed для вырезанияпервый и последний разделитель и пробелы перед и после каждого разделителя, ввод теперь такой:

jdoe|John Doe|555-1212||1/1/11|workstation1, server1|added by me

Вот что я пробовал:

oIFS="$IFS"; IFS='|'
for line in `cat $userList`; do
  arr=("$line")
  echo "Username: ${arr[0]}"  #not assigning a variable, just testing the output
  echo "Full Name: ${arr[1]}"
  echo "Phone 1: ${arr[2]}"
  echo "Phone 2: ${arr[3]}"
  # etc..
done
IFS="$oIFS"

Вывод:

Username: 
Full Name: 
Phone 1:
Phone 2:
Username: jdoe
Full Name: 
Phone 1:
Phone 2:
Username: John Doe
Full Name: 
Phone 1:
Phone 2:

Еще одна вещь, которую я попробовал:

for line in `cat $userList`; do
  arr=(${line//|/ })
  echo "Username: ${arr[0]}"
  echo "Full Name: ${arr[1]}"
  echo "Phone 1: ${arr[2]}"
  echo "Phone 2: ${arr[3]}"
  # etc
done

Вывод:

Username: jdoe
Full Name: John
Phone 1:
Phone 2:
Username: Doe
Full Name: 555-1212
Phone 1:
Phone 2:

Есть предложения?Спасибо !!


Решено: согласно первому предложению ниже, скрипт теперь выглядит так:

#!/bin/bash
userList=`cat userlist | sed 's/^|//; s/|$//; s/[ ]*|[ ]*/|/g;'`
oIFS="$IFS"; IFS=$'\n'
for line in $userList; do
  IFS='|'
  arr=($line)
  echo "Username: ${arr[0]}"
  echo "Full Name: ${arr[1]}"
  echo "Phone 1: ${arr[2]}"
  echo "Phone 2: ${arr[3]}"
  #etc
done
IFS="$oIFS"

Вывод:

Username: jdoe
Full Name: John Doe
Phone 1: 555-1212
Phone 2: 
Username: jdoe2
Full Name: Jane Doe
Phone 1: 555-1212
Phone 2:

Работает как шарм, большое спасибо!Я не пробовал другие предложения ниже, но в следующий раз мне нужно будет сделать что-то подобное.Спасибо всем!

Ответы [ 4 ]

9 голосов
/ 30 декабря 2011

Ваша первая попытка довольно близка. Основными проблемами являются следующие:

  • for line in `cat $userList` разбивает файл на $IFS, а не на разрыв строки. Поэтому вы должны установить IFS=$'\n' перед циклом и IFS='|' внутри цикла. (Кстати, стоит отметить, что подход for ... in `cat ...` считывает весь файл и затем разделяет его, так что это не лучший подход, если файл может быть большим. Подход на основе read был бы лучше в этом случае.)
  • arr=("$line"), заключая $line в двойные кавычки, предотвращает расщепление слов и поэтому делает $IFS неактуальным. Это должно быть просто arr=($line).
  • Так как $line имеет ведущую трубу, вам нужно либо удалить ее, прежде чем вы доберетесь до arr=($line) (написав что-то вроде $line="${line#|}"), либо вам нужно обработать arr как основанную на 1 массив (так как ${arr[0]}, часть перед первым каналом будет пустой).

Собрав все вместе, вы получите что-то вроде этого:

oIFS="$IFS"
IFS=$'\n'
for line in `cat $userList`; do
  IFS='|'
  arr=($line)
  echo "Username: ${arr[1]}"  #not assigning a variable, just testing the output
  echo "Full Name: ${arr[2]}"
  echo "Phone 1: ${arr[3]}"
  echo "Phone 2: ${arr[4]}"
  # etc..
done
IFS="$oIFS"

(Примечание: меня не беспокоили начальные и конечные пробелы полей из-за части «Я могу сделать этот шаг отдельно» ... или я не так понял? Вам нужна помощь и с этой частью?) ?)

2 голосов
/ 31 декабря 2011
IFS='|'
while read username fullname phone1 phone2 dateadded servers comments; do
    printf 'username: %s\n' "$username"
    printf 'fullname: %s\n' "$fullname"
    printf 'phone1: %s\n' "$phone1"
    printf 'phone2: %s\n' "$phone2"
    printf 'date added: %s\n' "$dateadded"
    printf 'servers: %s\n' "$servers"
    printf 'comments: %s\n' "$comments"
done < infile.txt
1 голос
/ 31 декабря 2011

Другое решение:

shopt -s extglob

infile='user.lst'
declare -a label=( "" "Username" "Full Name" "Phone 1" "Phone 2"  )

while IFS='|' read  -a fld ; do
  for (( n=1; n<${#label[@]}; n+=1 )); do
    item=${fld[n]}
    item=${item##+([[:space:]])}
    echo  "${label[n]}:  ${item%%+([[:space:]])}"
  done
done < "$infile"

Ведущие и конечные пробелы будут удалены.

0 голосов
/ 16 марта 2017

Использование массивов и paste.Не учитывает пустые поля, так как OP сказал, что это не обязательное требование.

userList='jdoe|John Doe|555-1212||1/1/11|workstation1, server1|added by me'

fields=("Username: " "Full Name: " "Phone 1: " "Phone 2: " "Date_added: " "Servers: " "Comments: ")

IFS='|' read -ra data <<<${userList}

paste <(IFS=$'\n'; echo "${fields[*]}") <(IFS=$'\n'; echo "${data[*]}")

Username:       jdoe
Full Name:      John Doe
Phone 1:        555-1212
Phone 2: 
Date_added:     1/1/11
Servers:        workstation1, server1
Comments:       added by me
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...