bash 在带有变量和正则表达式的 for 循环中使用 sed
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15574641/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Using sed in a for loop with variables and regex
提问by SteveHNH
I'm trying to build a script where a portion of it utilizes 'sed' to tag the filename onto the end of each line in that file, then dumps the output to a master list. The part of the script giving me trouble is sed here:
我正在尝试构建一个脚本,其中的一部分利用“sed”将文件名标记到该文件中每一行的末尾,然后将输出转储到主列表。给我带来麻烦的脚本部分在这里 sed:
DIR=/var/www/flatuser
FILES=$DIR/*
for f in $FILES
do
echo "processing $f file...."
sed -i "s/$/:$f/" $f
cat $f >> $DIR/master.txt
done
The issue is that the 'sed' statement works fine outside of the for loop, but when I place it in the script, I believe it's having issues interpreting the dollar signs. I've tried nearly every combo of " and ' that I can think of to get it to interpret the variable and it continuously either puts "$f" at the end of each line, or it fails outright.
问题是“sed”语句在 for 循环之外工作正常,但是当我将它放入脚本时,我相信它在解释美元符号时遇到了问题。我已经尝试了几乎所有我能想到的 " 和 ' 组合来解释变量,并且它不断地将“$ f”放在每行的末尾,或者它完全失败。
Thanks for any input!
感谢您提供任何意见!
回答by chepner
You just need to escape the dollar sign:
你只需要转义美元符号:
sed -i "s/$/:$f/" "$f"
so that the shell passes it literally to sed.
以便外壳将其逐字传递给sed.
To expand on Charles Duffy's point about quoting variables:
扩展 Charles Duffy 关于引用变量的观点:
DIR=/var/www/flatuser
for f in "$DIR"/*
do
echo "processing $f file...."
sed -i "s/$/:${f##*/}/" "$f"
cat "$f" >> "$DIR/master.txt"
done
If any file names contain a space, it's too late to do anything about it if you assign the list of file names to $FILES; you can no longer distinguish between spaces that belong to file names and spaces that separate file names. You could use an array instead, but it's simpler to just put the glob directly in the for loop. Here's how you would use an array:
如果任何文件名包含空格,如果您将文件名列表分配给$FILES; 您无法再区分属于文件名的空格和分隔文件名的空格。您可以改用数组,但将 glob 直接放入 for 循环更简单。以下是您将如何使用数组:
DIR=/var/www/flatuser
FILES=( "$DIR"/* )
for f in "${FILES[@]}"
do
echo "processing $f file...."
sed -i "s/$/:${f##*/}/" "$f"
cat "$f" >> "$DIR/master.txt"
done
For versions of sedthat don't use -i, here's a way to explicitly handle the temp file needed to simulate in-place editing:
对于sed不使用的版本-i,这里有一种显式处理模拟就地编辑所需的临时文件的方法:
t=$(mktmp sXXXX); sed "s/$/:$f/" "$f" > "$t"; mv "$t" "$f" && rm "$t"
回答by Charles Duffy
Personally, I'd do this like so:
就个人而言,我会这样做:
dir=/var/www/flatuser
for f in "$dir"/*; do
[[ $f = */master.txt ]] && continue
while read -r; do printf '%s:%s\n' "$REPLY" "${f##*/}"; done <"$f"
done >/var/www/flatuser/master.txt
It doesn't modify your files in-place the way sed -idoes, so it's safe to run more than one time (the sed -iversion will add the names to your files in-place every time it runs, so you'll end up with each line having more than one copy of the filename on it).
它不会像那样就地修改您的文件sed -i,因此运行多次是安全的(该sed -i版本每次运行时都会将名称就地添加到您的文件中,因此您最终会得到每一行上面有不止一份文件名副本)。
Also, sed -iisn't specified by POSIX, so not all operating systems will have it.
此外,sed -iPOSIX 未指定,因此并非所有操作系统都具有它。
回答by pepper
The problem is NOT the dollar sign. It's that the variable $f contains a "/" character, and sed is using that to separate expressions. Try using "@" as the separator.
问题不是美元符号。这是变量 $f 包含一个“/”字符,而 sed 正在使用它来分隔表达式。尝试使用“@”作为分隔符。
DIR=/var/www/flatuser
FILES=$DIR/*
for f in $FILES
do
echo "processing $f file...."
sed -i s@"$"@:"$f"@ $f
cat $f >> $DIR/master.txt
done
回答by D-Day
it's old, but maybe it helps someone. Why not basename the file to get rid of leading directory
它很旧,但也许它可以帮助某人。为什么不为文件命名以摆脱前导目录
DIR=/var/www/flatuser
FILES=( "$DIR"/* )
for f in "${FILES[@]}"
do
echo "processing $f file...."
b=`basename $f`
sed -i "s/$/:${b##*/}/" "$b"
cat "$f" >> "$DIR/master.txt"
done
not tested ...
未测试...

