1

我正在尝试构建一个脚本,其中一部分利用“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

问题是“sed”语句在 for 循环之外工作正常,但是当我将它放在脚本中时,我相信它在解释美元符号时遇到了问题。我已经尝试了几乎所有我能想到的 " 和 ' 组合来解释变量,并且它不断地将 "$f" 放在每行的末尾,或者完全失败。

感谢您的任何意见!

4

4 回答 4

5

您只需要转义美元符号:

sed -i "s/\$/:$f/" "$f"

以便外壳将其逐字传递给sed.

扩展 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

如果任何文件名包含空格,那么如果将文件名列表分配给$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

对于sed不使用的版本,-i这是一种显式处理模拟就地编辑所需的临时文件的方法:

t=$(mktmp sXXXX); sed "s/\$/:$f/" "$f" > "$t"; mv "$t" "$f" && rm "$t"
于 2013-03-22T16:00:11.323 回答
3

就个人而言,我会这样做:

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

它不会像这样就地修改您的文件sed -i,因此运行多次是安全的(该sed -i版本每次运行时都会将名称添加到您的文件中,因此您最终会得到每一行有多个文件名的副本)。

此外,sed -iPOSIX 未指定,因此并非所有操作系统都有它。

于 2013-03-22T16:11:54.023 回答
0

它很旧,但也许它可以帮助某人。为什么不为文件命名以摆脱前导目录

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

没有测试...

于 2014-07-16T08:09:39.713 回答
0

问题不在于美元符号。就是变量 $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
于 2013-03-22T16:24:08.040 回答