【问题标题】:sed command is not working properly when using wildcard使用通配符时 sed 命令无法正常工作
【发布时间】:2020-05-30 20:29:38
【问题描述】:

我正在尝试使用“sed”命令删除与作为命令行参数给出的通配符模式匹配的文件的最后一行,并将文件从该目录移动到当前目录。代码如下:

DIR="/home/usr_name/trash/"
for file in "$@"
    do
        if [ $file != "-h" ] //ignore this line
        then
            temp="$DIR$file"
            sed '$d' "$DIR$file"
            mv $temp .
        fi
    done

代码正在移动文件,但没有执行“sed”命令来删除最后一行。将通配符设为 ab* ,会出现以下错误:

sed: can't read /home/usr_name/trash/ab*: No such file or directory

帮我弄清楚这种情况。

【问题讨论】:

  • @sergio ab* 表示我要移动所有名称以 ab 开头的文件。
  • 顺便说一句:看看 sed 的选项-i
  • 通配符由 shell 完成,"$DIR$file" 被引用,因此找不到文件。
  • 所以,文件从垃圾箱 ($DIR) 开始,应该由 sed 内联编辑,然后从垃圾箱移动到您运行脚本的目录?
  • sed 没有-i 选项不会更改文件本身,它会将编辑后的版本发送到标准输出。我认为您要么需要使用sed -i(它进行就地编辑),要么使用sed '$d' "$DIR$file" >"$file" 将垃圾文件留在原处并将编辑后的版本放在当前目录中。顺便说一句,有几个地方应该在变量引用周围加上双引号;我推荐shellcheck.net 指出这样的问题。

标签: linux bash shell sed wildcard


【解决方案1】:

当你跑步时

yourcript ab*

shell 尝试在当前目录中展开通配符,然后将结果作为"$@" 传递。如果当前目录中没有匹配项,则 扩展 通配符(在 shell 的传统默认配置中)现在是 literal 字符串 ab*,并且不会进一步扩展通配符尝试。

(Bash 有 nullglob 来改变这种行为,因此不匹配任何文件的通配符会被替换为空;但这在这里并没有真正的帮助。)

如果通配符 确实 匹配某些文件,则这些文件很可能不会存在于其他目录中, 或者(在一般情况下)具有这些名称的文件将不是您实际想要处理的文件。

在最坏的情况下,可能当前目录中的一些文件匹配通配符并且它们都在目标目录中重复具有相同名称的文件。所以如果你在当前目录和另一个目录中都有ababc,但是另一个目录也包含abecedaryabugida,你的命令只会处理前两个,你不会收到警告其他两个从未匹配和处理。

底线,可能会重新考虑将要处理的文件的完整路径传递给脚本的方法;然后,剩下的就很简单了,您的脚本的行为将是可预测的,并且与其他文件处理实用程序的行为一致。

您仍然需要让sed 实际修改每个文件。只是sed '$d' files不会改变files,只是将修改后的内容打印到标准输出。如果你有sed -i,可能会使用它。

for file in "$@"
do
    # Note added quotes
    if [ "$file" != "-h" ] # ignore this line
    then
        sed -i '$d' "$file"
        mv "$file" .
    fi
done

用法:

yourscript /home/usr_name/trash/ab*

【讨论】:

  • 对,对不起,我在这里做的一团糟。我删除了我的帖子。
  • @Jetchisel 我喜欢你回答的基本思想;它真的不应该得到这么多的反对票。 ed 在这个时代绝对是一个边缘工具,所以可能有几个反对者并没有真正理解你的建议。
【解决方案2】:

如果您需要通配符,最简单的解决方案是使用 find:

find "$DIR" -name "$file" \
   -exec sed -i '$d' {} \; 
   -exec mv {} "$DEST" \;
  • -name "$file" - 这将告诉 find 搜索匹配通配符的文件
  • -exec sed -i '$d' {} \;- 对找到的每个文件执行 sed {} 代表该文件
  • -exec mv {} "$DEST" \; - 移动文件

请注意执行的顺序,移动后文件在旧位置将不可用。

编辑:我最初假设'ab*' 是作为引用参数提供给整个脚本的。这个answer 让我想起了另一种可能性:您从没有任何以“ab”开头的文件的目录运行脚本,在这种情况下,“ab*”不会被扩展,并且 mv 将在您的脚本中工作,但 sed 不是(因为您引用了“$DIR$file”,请参阅 bash 的调试输出:

sorin@testvm ~/tmp $ seq 1 2 > src/ab1
sorin@testvm ~/tmp $ seq 1 4 > src/ab5
sorin@testvm ~/tmp $ seq 1 3 > src/ab3
sorin@testvm ~/tmp $ bash -x test.sh ab*
+ DIR=src/
+ for file in '"$@"'
+ '[' 'ab*' '!=' -h ']'
+ temp='src/ab*'
+ sed '$d' 'src/ab*'
sed: can't read src/ab*: No such file or directory
+ mv src/ab1 src/ab3 src/ab5 .
sorin@testvm ~/tmp $

这完全涵盖了您问题中描述的场景。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多