【问题标题】:bash string to array with spaces and extra delimitersbash 字符串到带有空格和额外分隔符的数组
【发布时间】:2012-01-30 18:21:27
【问题描述】:

我正在尝试从以竖线 ("|") 作为分隔符并包含空格的字符串创建数组。我已经环顾了一段时间,感谢How do I split a string on a delimiter in Bash?Splitting string into array 等来源,我已经接近了。我很接近,但它不是很有效。两个主要问题是字符串中有空格,有开始和结束分隔符,还有一些字段是空白的。此外,我需要将它们分配给变量,而不是仅仅回显这些值。 以下是源数据的格式:

|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:

有什么建议吗?谢谢!!

【问题讨论】:

  • 这在 perl 或 ruby​​ 中是微不足道的,有什么理由不使用其中之一?
  • 我同意“使用 perl”的评论,但如果你想要一种仅限 bash 的方法,为什么不至少使用 'sed' 或其他东西来去除“|”前后的空格? "角色,至少让你自己更轻松
  • Perl 是一个选项,但我不熟悉它。我添加了一个 sed 行来删除前导/尾随分隔符和空格,更新问题。
  • @ennuikiller 这在 bash 中和在 perl 或 ruby​​ 中一样微不足道。
  • @Martin 我可能会建议您尝试下面的 fgm 答案。恕我直言,这是最合适的答案。另外,看看我的 cmets 对他的回答也是如此。

标签: arrays string bash delimiter


【解决方案1】:

使用数组和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

【讨论】:

    【解决方案2】:

    另一种解决方案:

    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"
    

    前导和尾随空格将被删除。

    【讨论】:

    • 这是迄今为止最接近的解决方案,但是您的 PE 不会删除 任意 数量的空格,只有一个。您可以通过使用shopt -s extglob 和使用${item##+([[:space:]])}${item%%+([[:space:]])} 来解决此问题
    • 另外,如果他决定添加另一个字段,我是否建议您使用for ((n=1; n&lt;=${#label[@]}; n++)) 更灵活
    【解决方案3】:
    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
    

    【讨论】:

    • 有趣的是,我没有看到前面提到的IFS='|',所以我想知道如果不设置IFS,它会如何工作。对此感到抱歉。
    • @JaypalSingh SO 让您在新帖子开始跟踪编辑之前有几秒钟的时间来编辑它。当我最初发布此内容时,我错误地粘贴了 IFS 行,但我在 12 秒内就完成了。你很快。 ;)
    【解决方案4】:

    您的第一次尝试非常接近。主要问题如下:

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

    (注意:我不担心字段的前导和尾随空格,因为“我可以单独执行该步骤”部分......还是我误解了?你是否也需要这部分的帮助?)

    【讨论】:

    • OP 使用`cat $userList`,但$(&lt;"$userList") 更可取。
    猜你喜欢
    • 2023-04-01
    • 1970-01-01
    • 2016-02-25
    • 2012-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-16
    相关资源
    最近更新 更多