替换UNIX文件第一行中的字符串

替换UNIX文件第一行中的字符串,unix,awk,sed,grep,Unix,Awk,Sed,Grep,我想替换出现在第一行中的字符串,尽管它也出现在文件的其余行中。如何通过shell脚本实现这一点?有人能帮我一下吗。我的代码如下。我正在从文件中提取第一行,之后我不确定如何进行替换。任何帮助都将不胜感激。谢谢 伙计们,我想替换$line中的一个字符串,并将新行写入同一位置的同一个文件中 代码: while read line do if [[ $v_counter == 0 ]] then echo "$line"

我想替换出现在第一行中的字符串,尽管它也出现在文件的其余行中。如何通过shell脚本实现这一点?有人能帮我一下吗。我的代码如下。我正在从文件中提取第一行,之后我不确定如何进行替换。任何帮助都将不胜感激。谢谢

伙计们,我想替换$line中的一个字符串,并将新行写入同一位置的同一个文件中

代码:

while read line
do
        if [[ $v_counter == 0 ]] then
                echo "$line"

                v_counter=$(($v_counter + 1));
        fi
done < "$v_Full_File_Nm"
输出

    BUXT_CMPID|MEDICAL_RECORD_NUM|FACILITY_ID|PATIENT_LAST_NAME|PATIENT_FIRST_NAME|HOME_ADDRESS_LINE_1|HOME_ADDRESS_LINE_2|HOME_CITY|HOME_STATE|HOME_ZIP|MOSAIC_CODE|MOSAIC_DESC|DRIVE_TIME| buxt_pt_apnd_20140624_head_5records.txt
100106086|5000120878|7141|HARRIS|NEDRA|6246 PARALLEL PKWY||KANSAS CITY|KS|66102|S71|Tough Times|2|buxt_pt_apnd_20140624_head_5records.txt
BUXT_CMPID|MEDICAL_RECORD_NUM|FACILITY_ID|PATIENT_LAST_NAME|PATIENT_FIRST_NAME|HOME_ADDRESS_LINE_1|HOME_ADDRESS_LINE_2|HOME_CITY|HOME_STATE|HOME_ZIP|MOSAIC_CODE|MOSAIC_DESC|DRIVE_TIME| SRC_FILE_NM
100106086|5000120878|7141|HARRIS|NEDRA|6246 PARALLEL PKWY||KANSAS CITY|KS|66102|S71|Tough Times|2|buxt_pt_apnd_20140624_head_5records.txt
根据以上示例数据,我需要将buxt\u pt\u apnd\u 20140624\u head\u 5records.txt替换为SRC\u FILE\u NAME字符串

awk -v old="string1" -v new="string2" '
NR==1 && (idx=index($0,old)) {
    $0 = substr($0,1,idx-1) new substr($0,idx+length(old))
}
1' file > /usr/tmp/tmp$$ && mv /usr/tmp/tmp$$ file
仅当出现在
文件
的第一行时,上述内容才会将
string1
替换为
string2

发布的任何使用awk但不使用
索引的解决方案通常都不起作用。使用sed发布的任何解决方案也是如此。原因是,这些将在REs上工作,而不是在字符串上,因此根据
string1
中存在的字符,在替换字符串时表现不理想

看起来OPs将与sed重新替换解决方案一起使用,因此这仅适用于希望替换字符串的任何其他人:如果您不希望将字符串替换函数内联,则字符串替换函数的外观如下所示:

awk -v old="string1" -v new="string2" '
function strsub(old,new,tgt,     idx) {
    if ( idx = index(tgt,old) ) {
        tgt = substr(tgt,1,idx-1) new substr(tgt,idx+length(old))
    }
    return tgt
}
NR==1 { $0 = strsub(old,new,$0) }
1' file
bash解决方案:

file="afile.txt"
str="hello"
repl="goodbye"

IFS= read -r line < "$file"
line=${line/$str/$repl}

tmpfile="/usr/tmp/$file.$$.tmp"

{
  echo "$line"
  tail -n+2 "$file"
} > "$tmpfile" && mv "$tmpfile" "$file"
file=“afile.txt”
str=“你好”
repl=“再见”
IFS=读取-r行<“$file”
line=${line/$str/$repl}
tmpfile=“/usr/tmp/$file.$$.tmp”
{
回音“$line”
尾部-n+2“$file”
}>“$tmpfile”和&mv“$tmpfile”“$file”

注意,上面的
$str
将被解释为一种“模式”(一种简单的正则表达式),其中
*
匹配任意数量的字符,
匹配任意单个字符,
[abc]
匹配括号中的任意一个字符,
[^abc]
(或
[!abc]
)匹配不在括号中的任何一个字符。请参见为什么不使用
sed

sed -e '1s/fred/frog/' yourfile
将第1行的fred替换为frog

如果您的“字符串”是一个变量,您可以这样做来展开变量:

sed -e "1s/$varA/$varB/" yourfile

如果要就地执行并更改文件,请将
-i
添加到
-e

之前UNIX shell是一个调用工具的环境。操纵文本文件的UNIX工具是awk。因此,编写一个awk脚本并从shell调用它。您发布的示例数据只包含一行,但在您的文本中听起来,解决方案不替换后续行中的字符串很重要,因此您应该发布一些示例输入/输出tht,以演示您需求的这一方面。另外-如果目标字符串在第一行出现多次怎么办?如果它作为另一个字符串的一部分出现会怎样?对于
awk
是否有一个
-i
类型选项,就像对于
sed
一样?是的,GNU awk的较新版本中有
-i替代了
-i
,但是,像sed一样,它只是隐藏了您正在使用tmp文件的事实,它不会改变您正在使用tmp文件的事实。@SOaddict谢谢。sed的“解决方案”当然更简单,但老实说,它是一个简单的解决方案,因为在搜索和替换“字符串”中有各种各样的字符组合,它们会以奇怪的方式完全搞乱文件。如果幸运的话,它们会产生语法错误,如果不是,它们只会悄悄地替换错误的字符串和/或用错误的替换文本替换正确的字符串。如果这是一个学校项目,那么最坏的情况是你的老师会批评你,但如果这是一个真正的商业应用程序,我会避免这个问题的sed解决方案。这不会取代字符串,而是取代一个正则表达式,这是一个非常不同的情况。@EdMorton改为
bash
解决方案。谢谢你的指针。那不是还在用REs而不是字符串操作吗?它现在还有其他问题,例如,它将在输入行的任何位置用文本制表符替换字符串
\t
,并去掉任何前导/尾随空格,如果您无法创建tmp文件,您将删除原始文件的内容。@EdMorton我不确定它将如何用制表符替换\t(例如,
echo
仅通过
-e
开关执行此操作,
read
似乎根本不执行此操作)。
read
可以通过将
IFS
设置为空字符串来强制不去除前导/尾随空格。停止它对原始文件的重击非常简单(我认为).但是您是对的,replace命令使用了一种正则表达式(其中*和?和[…]是特殊的),所以这不好。我现在正在寻找替代方案…read解释转义序列,如
\t
,除非您为
raw
添加
-r
标志。每次使用
read
时,您都应该编写
IFS=read-r…
,除非您有非常明确的理由不理解所有警告,有点像yo你应该总是引用你的变量。嗯,也许没有-r read,只是去掉了反斜杠,我永远记不起来了。无论如何,shell中的默认行为似乎从来没有像你通常希望的那样,只留下那些乱七八糟的文本,这太糟糕了,但我想比我更伟大的头脑有理由这样做……这并不能代替字符串,它会重放ces是一个正则表达式,这是一种完全不同的情况。@EdMorton-虽然你严格地说是正确的,但我认为就这个问题而言,
sed
作为一个工具很好。它似乎比
awk
更简单。我认为我们不应该猜测OPs字符串可能包含或不包含哪些字符。发布的一个示例是o far包含一个RE元字符。与上述awk中的sed脚本等效的是
awk'NR==1{sub(/fred/,“frog”)}1'yourfile
,它并不比sed解决方案复杂,您只需要