我需要将 file.txt 读入 Bash 数组。然后我需要删除空格、双引号和每个条目中除了第一个逗号之外的所有内容。这是我已经走了多远:
$ cat file.txt
10,this
2 0 , i s
30,"all"
40,I
50,n,e,e,d,2
60",s e,e"
$ cat script.sh
#!/bin/bash
readarray -t ARRAY<$1
ARRAY=( "${ARRAY[@]// /}" )
ARRAY=( "${ARRAY[@]//\"/}" )
for ELEMENT in "${ARRAY[@]}";do
echo "|ELEMENT|$ELEMENT|"
done
$ ./script.sh file.txt
|ELEMENT|10,this|
|ELEMENT|20,is|
|ELEMENT|30,all|
|ELEMENT|40,I|
|ELEMENT|50,n,e,e,d,2|
|ELEMENT|60,se,e|
除了逗号的情况之外,这很有效。我知道有多种方法可以给这只猫剥皮,但由于这是较大的脚本的一部分,我真的很想使用参数替换来到达这里:
|ELEMENT|10,this|
|ELEMENT|20,is|
|ELEMENT|30,all|
|ELEMENT|40,I|
|ELEMENT|50,need2|
|ELEMENT|60,see|
这可以通过参数替换实现吗?
答案1
据我所知,不需要将其读入数组bash
来创建该输出:
$ sed 's/[ "]//g; s/,/ /; s/,//g; s/ /,/; s/.*/|ELEMENT|&|/' <file
|ELEMENT|10,this|
|ELEMENT|20,is|
|ELEMENT|30,all|
|ELEMENT|40,I|
|ELEMENT|50,need2|
|ELEMENT|60,see|
该sed
表达式删除空格和双引号,用空格替换第一个逗号(此时字符串中没有其他空格),删除所有其他逗号,恢复第一个逗号,并在前面添加和附加额外的数据。
或者,使用 GNU sed
:
sed 's/[ "]//g; s/,//2g; s/.*/|ELEMENT|&|/' <file
(标准不支持和作为命令标志sed
的组合)。2
g
s
答案2
我会删除您需要删除的内容sed
前加载到数组中(另请注意小写变量名称,一般来说,最好避免在 shell 脚本中使用大写变量):
#!/bin/bash
readarray -t array< <(sed 's/"//g; s/ *//g; s/,/"/; s/,//g; s/"/,/' "$1")
for element in "${array[@]}";do
echo "|ELEMENT|$element|"
done
这会在示例文件中生成以下输出:
$ foo.sh file
|ELEMENT|10,this|
|ELEMENT|20,is|
|ELEMENT|30,all|
|ELEMENT|40,I|
|ELEMENT|50,need2|
|ELEMENT|60,see|
如果您确实必须使用参数替换,请尝试以下操作:
#!/bin/bash
readarray -t array< "$1"
array=( "${array[@]// /}" )
array=( "${array[@]//\"/}" )
array=( "${array[@]/,/\"}" )
array=( "${array[@]//,/}" )
array=( "${array[@]/\"/,}" )
for element in "${array[@]}"; do
echo "|ELEMENT|$element|"
done
答案3
ELEMENT='50,n,e,e,d,2'
IFS=, read -r first rest <<<"$ELEMENT"
printf "%s,%s\n" "$first" "${rest//,/}"
50,need2
改掉使用全大写变量名的习惯。您最终将与诸如 PATH 之类的关键“系统”变量发生冲突并破坏您的代码。
答案4
您可以循环数组并使用中间变量:
for((i=0; i < "${#ARRAY[@]}"; i++))
do
rest="${ARRAY[i]#*,}"
ARRAY[i]="${ARRAY[i]%%,*}","${rest//,/}"
done
这将分配给rest
第一个逗号后的部分;然后我们将三部分连接回原始变量:
- 第一个逗号之前的部分
- 一个逗号
rest
将每个逗号替换为空