【问题标题】:Replace a word stored in a variable替换存储在变量中的单词
【发布时间】:2014-10-02 12:10:53
【问题描述】:
#!/bin/bash
IFS=''
replace="XXX"
for line in `cat test.csv`;do
name=`echo $line|cut -d"|" -f1`
      date=`echo $line|cut -d"|" -f3`
      echo $name
      echo $date
      sed -n "s/$name/XXX/gpw" output' test.csv
done

我需要将$name 的值替换为XXX,但它不起作用。

CSV 文件包含:

38880|update|20121227|customerXXXX|CXXX|Credit|Comp any|channel:XXX|XXX|XXX|0|Active|N|N|2012-12-31 17:37:46|Y|2012-12-31 17:37:46

错误是:

sed: -e expression #1, char 8: unterminated `s' command

【问题讨论】:

  • @AshishTripurwar 当然这不是脚本的逐字副本,因为其中有一个无与伦比的'。还有其他复制粘贴错误吗? (此外,还有一些其他小问题;通过shellcheck.net 运行它。)
  • 你应该真正指出你想要的输出是什么。

标签: bash shell unix sed


【解决方案1】:

我认为您只是为了更改第一列而做了太多事情。

这应该是:

awk -v subs="XXX" 'BEGIN{FS=OFS="|"} {$1=subs}1' file

对于给定的输入,它会返回:

XXX|update|20121227|customerXXXX|CXXX|Credit|Comp any|channel:XXX|XXX|XXX|0|Active|N|N|2012-12-31 17:37:46|Y|2012-12-31 17:37:46

要更新您的文件,请使用:

awk -v subs="XXX" 'BEGIN{FS=OFS="|"} {$1=subs}1' file > new_file && mv new_file file

如果你需要使用 bash,你可以像这样使用IFSread

while IFS="|" read -r name _ date _
do
   echo $name
   echo $date
   sed -i.bak "s/$name/XXX/g" another_file #do the replacement
done < file

注意$name 获取第一个字段的值,$date 获取第三个字段的值,基于| 作为分隔符。

【讨论】:

  • 感谢它完全与 awk 一起工作,但我需要传递列名而不是 $3 你能建议吗
  • 什么意思?需要注明列号吗?此外,您最好更新您的问题,以便每个人都清楚您想要什么。
【解决方案2】:

首先,使用while 代替for 可以大大简化事情。您也不需要sed。 Bash 和其他 shell 有一些相当广泛的 string manipulation abilities。因此,您的脚本的工作版本可能是:

$ while IFS='|' read -r name rest; do 
    printf "XXX|%s\n" "$rest"
 done < test.csv > new.csv
XXX|update|20121227|customerXXXX|CXXX|Credit|Comp any|channel:XXX|XXX|XXX|0|Active|N|N|2012-12-31 17:37:46|Y|2012-12-31 17:37:46

这会将新行写入new.csv 文件。如果您还想将 $name$date 的值回显到终端但只保存更改的文件,请改用:

$ > new.csv; while IFS='|' read -r name f2 date rest; do 
    printf "%s\n%s\n" "$date" "$name" 
    printf "XXX|%s|%s|%s\n" "$f2" "$date" "$rest" >> new.csv
 done < test.csv 

你似乎也想做更多的操作。如果是这样,您可以将每个字段读入一个变量:

while IFS='|' read -r f{1..10}; do ... ;done; done < test.csv 

这些字段将以$f1$f15 的形式提供。或者,您可以使用数组:

$ while IFS='|' read -r -a fields; do 
    for((i=0; i<${#fields[@]}; i++)); do 
        echo "Field $i : ${fields[$i]}" 
    done 
done < test.csv 
Field 0 : 38880
Field 1 : update
Field 2 : 20121227
Field 3 : customerXXXX
Field 4 : CXXX
Field 5 : Credit
Field 6 : Comp any
Field 7 : channel:XXX
Field 8 : XXX
Field 9 : XXX
Field 10 : 0
Field 11 : Active
Field 12 : N
Field 13 : N
Field 14 : 2012-12-31 17:37:46
Field 15 : Y
Field 16 : 2012-12-31 17:37:46

【讨论】:

  • 它正在工作,但我需要在文件中永久替换,请您建议
  • @AshishTripurwar 在什么文件中?如果您使用我的建议,您可以读取输入文件,然后将输出重定向到输出文件。查看更新的答案。
  • 由于 OP 只想使用第一列和第三列,我建议改为使用 while read -r name _ date _
  • 没有第二个根本不起作用是的,我已经重定向了输出,但它只打印修改后的列
  • @fedorqui 因为 OP 实际上并没有对日期做任何事情,但我认为它只是用于调试。没有理由假设这一点,所以编辑了答案。谢谢。
【解决方案3】:
sed 'h;s/^\([^|]*\)|[^|]*|\([^|]*\)|.*/\1\
\2/p
g
:a
s/^\([^|]*\)\(|.*\)\1/\1\2XXX/
t a
s/^\([^|]*\)|/XXX|/' test.csv

试试这个。

  1. 提取并打印姓名+日期
  2. 递归替换行中的名称
  3. 替换第一次出现的名字

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-04-14
    • 1970-01-01
    • 2011-11-30
    • 2022-11-17
    • 2020-03-23
    • 2021-10-14
    • 2021-05-10
    • 1970-01-01
    相关资源
    最近更新 更多