如何在bash脚本中拆分制表符分隔的字符串而不删除空格?

时间:2013-11-01 02:17:54

标签: bash string-split tab-delimited

我在$LINE中有我的字符串,我希望$ITEMS成为此版本的版本,在单个标签保留空白上拆分。这就是我现在所处的位置:

IFS=$'\n' ITEMS=($(echo "$LINE" | tr "\t" "\n"))

这里的问题是IFS是一个或多个,所以它吞噬了新行,标签,等等。我已根据此处发布的其他问题尝试了其他一些事情,但他们认为所有领域都会有值,永远不会是空白。并且the one that seems to hold the key远远超出了我并在整个文件上运行(我只是拆分一个字符串)。

我的偏好是纯BASH解决方案。

5 个答案:

答案 0 :(得分:3)

如果字符是空格,则

IFS只有一个或多个。非空白字符是单个分隔符。所以一个简单的解决方案,如果您确信某个非空白字符不在您的字符串中,则将标签转换为该字符然后拆分:

IFS=$'\2' read -ra ITEMS <<<"${LINE//$'\t'/$'\2'}"

不幸的是,诸如“输入中没有\2的实例”之类的假设在长期内往往会失败,其中“长期”会转换为“在最糟糕的时间”。所以你可能想分两步完成:

IFS=$'\2' read -ra TEMP < <(tr $'\t\2' $'\2\t' <<<"$LINE")
ITEMS=("${TEMP[@]//$'\t'/$'\2'}")

答案 1 :(得分:2)

一种可能性:使用IFS选项从字符串中-d制表符终止的“行”,而不是使用read进行拆分。但是,您需要确保字符串结束并使用标签,否则您将丢失最后一项。

items=()
while IFS='' read -r -d$'\t' x; do
   items+=( "$x" )
done <<< $'   foo   \t  bar\nbaz \t   foobar\t'

printf "===%s===\n" "${items[@]}"

使用

可以确保无需添加额外字段的尾随制表符
if [[ $str != *$'\t' ]]; then str+=$'\t'; fi

如有必要。

答案 2 :(得分:0)

line=$'zero\tone\ttwo'
IFS=$'\t' read -a arr <<< "${line}"
declare -p

输出

declare -a arr='([0]="zero" [1]="one" [2]="two")'

注意。这不涉及line中的换行符。

答案 3 :(得分:0)

纯粹的bash解决方案,只会在选项卡上拆分,并保留换行符和其他有趣的符号,如果有的话:

IFS=$'\t' read -r -a arr -d '' < <(printf '%s' "$line")

试一试:

$ line=$'zero\tone with\nnewlines\ttwo\t     three   \n\t\tfive\n'
$ IFS=$'\t' read -r -a arr -d '' < <(printf '%s' "$line")
$ declare -p arr
declare -a arr='([0]="zero" [1]="one with
newlines" [2]="two" [3]="     three   
" [4]="five
")'

正如您所看到的,这可以完美地运行:它保留所有内容(空格,换行符等),仅在制表符处进行拆分。

有一个缺点:它不处理“空字段”:观察line中有两个连续的标签;我们希望arr中有一个空字段,但事实并非如此。

另一个不那么明显的缺点:read的返回码是1,所以从技术上讲,对于Bash来说,这个命令有一个失败。这绝对不是问题,除非你使用set -eset -E,但不建议这样做(所以你不应该这样做。)

如果你能忍受这两个小缺点,这可能是理想的解决方案。

请注意,我们使用< <(printf '%s' "$line")而不是<<< "$line"来提供read,因为后者会插入一个尾随换行符。

答案 4 :(得分:0)

IFS特殊字符:

Words of the form $'string' are treated specially.  The word expands to
string, with backslash-escaped characters replaced as specified by  the
ANSI  C  standard.  Backslash escape sequences, if present, are decoded
as follows:
       \a     alert (bell)
       \b     backspace
       \e
       \E     an escape character
       \f     form feed
       \n     new line
       \r     carriage return
       \t     horizontal tab
       \v     vertical tab
       \\     backslash
       \'     single quote
       \"     double quote
       \?     question mark
       \nnn   the eight-bit character whose value is  the  octal  value
              nnn (one to three digits)
       \xHH   the  eight-bit  character  whose value is the hexadecimal
              value HH (one or two hex digits)
       \uHHHH the Unicode (ISO/IEC 10646) character whose value is  the
              hexadecimal value HHHH (one to four hex digits)
       \UHHHHHHHH
              the  Unicode (ISO/IEC 10646) character whose value is the
              hexadecimal value HHHHHHHH (one to eight hex digits)
       \cx    a control-x character 

展开的结果用单引号引起来,好像美元符号没有    在场。

双引号字符串前面加一个美元符号($“ string”)将导致    根据当前语言环境转换的字符串。如果    当前语言环境为C或POSIX,将忽略美元符号。如果    字符串被翻译和替换,替换用双引号引起来。