AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / unix / 问题 / 702418
Accepted
dungarian
dungarian
Asked: 2022-05-14 08:57:30 +0800 CST2022-05-14 08:57:30 +0800 CST 2022-05-14 08:57:30 +0800 CST

如何显示提示并防止执行基本但危险的命令,如 mv 或 rm

  • 772

客观的

每当我使用mv(或类似性质的命令)时,我希望我的 shell 提示我类似“嘿,你使用了 mv。对不起,但使用 mv -i 再做一次”。我想知道完成这种交互的合理方法。

目的是让我的电脑每次使用都会抱怨,mv所以我必须重新输入mv -i. 这样我就会发展肌肉记忆进入mv -i。

让我的电脑在引擎盖下转换我mv的不是目的,并且完全违背了意图。mv -i

如果这听起来像是一个愚蠢的想法,我想知道为什么和更好的解决方案。

背景

在过去,我曾使用mv并错误地覆盖了文件。虽然此评论建议以mv实际工作方式使用别名,但mv -i我同意此评论关于此类自定义的后果。与其习惯打字mv,我宁愿养成打字的习惯,mv -i这样我就不会在其他机器上搞砸了。

关注点

我担心此类修改会影响调用mv. mv有没有一种聪明的方法来中止并仅在我自己通过键入并按 Enter 执行时才显示提示?

笔记

  • 我备份文件,而不是相关的
  • 我知道我可以在我的桌子上贴便利贴或在墙上贴海报以提高认识
  • 环境:Debian、XFCE、xfce4-terminal、Bash
shell-script shell
  • 3 3 个回答
  • 74 Views

3 个回答

  • Voted
  1. glenn jackman
    2022-05-14T10:56:40+08:002022-05-14T10:56:40+08:00

    我会使用一个包装函数:你可以将它添加到你的 .bashrc (未经测试)

    mv () {
        case $1 in
            -*i*) # ok, used `mv -i ...`: invoke the mv command, passing all args
                command mv "$@"
                ;;
            *)
                echo "hey, use 'mv -i'" >&2
                false
                ;;
        esac
    }
    
    • 3
  2. White Owl
    2022-05-14T09:35:43+08:002022-05-14T09:35:43+08:00

    最简单的方法是创建别名。

    alias mv="mv -i"
    

    更复杂但更可定制的方法是创建一个mvshell 脚本,将其放入/bin,然后真正mv移动到/sbin或任何其他“秘密”目录。替换脚本将发出警告并mv通过完整路径调用原始脚本。

    如果您想完全拯救自己mv- 重命名或删除该工具。

    是的,其他脚本可能会由于此类修改而失败。在这种情况下,您可以进入这些脚本并修复它们,方法是替换mv为/secret/path/mv

    另一种方式 - 为日常生活创建一个特殊的用户。为他(通常在)创建一个排除危险工具$HOME/bin的真实副本。/bin为该日常用户设置一个 PATH 将使用/home/everyday/bin而不是/bin.
    如果某些应用程序现在需要“危险”工具——该应用程序不适合“日常”用户——切换到具有更多权限的用户。

    • 1
  3. Best Answer
    Stéphane Chazelas
    2022-05-16T11:33:46+08:002022-05-16T11:33:46+08:00

    虽然@glennJackman使用包装器的方法检查第一个参数是否以开头-并包含i在大多数常见情况下可能已经足够好,但在某些情况下它会失败:

    • 它妨碍了mv --help(不是--version包含-i)。
    • 它无法检测到-iin mv -v -i a b(或者当环境中没有时mv a b -iGNU允许的)。mvPOSIXLY_CORRECT
    • 它不包括 GNU的mv --interactive// mv --in...mv --i
    • 它错过-i了mv --no-target-dir a b或mv -Tdir file...

    对于涵盖所有这些情况的包装器,我们需要它以相同的方式解析其选项mv。没有两个实现以相同的方式解析它们的选项。您甚至会发现相同mv实现的版本之间的差异。

    mv(和大多数实用程序)的 GNU 实现将用于getopt_long()解析它们的选项。

    如果您的包装器可以getopt_long()使用相同的参数调用,我们将被排序。这留下了两个问题:

    1. 我们需要getopt_long()在shell中找到一个接口
    2. 我们需要弄清楚那些参数mv传递给getopt_long()

    如果您在 GNU/Linux 系统上,有可能的方法。

    getopt_long()虽然在 GNU 工具箱中没有 shell CLI ,但在util-linux: 它与andgetopt一起使用时的实用程序中有一个。-o-l

    在 GNU/Linux 上,GNU 实用程序将从getopt_long()libc 调用该函数,因为它将是 GNU libc,因此您可以使用ltracewhich traces library calls 来查看解析选项的getopt_long()调用。mv

    $ ltrace -e getopt_long mv -:
    mv->getopt_long(2, 0x7ffcf7febd68, "bfint:uvS:TZ", 0x5650dd02fb20, nilmv: invalid option -- ':'
    )                           = 63
    Try 'mv --help' for more information.
    +++ exited (status 1) +++
    

    (-:保证是一个虚假的选择)

    不够好,因为我们只看到了空头选项。然而,可以配置ltrace为在那里解码long_options参数,甚至隐藏我们不关心的参数。

    作为概念证明,这里有一个 zsh 脚本,它会sh为包装函数输出兼容代码,该函数在调用之前检查-i/ --interactive(或--help/ --version)或其缩写mv:

    #! /bin/zsh -
    set -o extendedglob
    die() {
      print -ru2 -- "$@"
      exit 1
    }
    
    for cmd do
      getopt_long_call=$(
        ltrace -F/dev/fd/3 3<<'EOF' -o/dev/fd/4 4>&1 > /dev/null 2>&1 -s 999 -A999 -e getopt_long "$cmd" -:
    int getopt_long(hide(int),hide(addr),string,array(struct(string,int,hide(int*),hide(int)),zero),hide(int*));
    EOF
      )
      getopt_long_call=${getopt_long_call%%$'\n'*}
    
      [[ $getopt_long_call = (#b)[^\"]#'getopt_long("'([^\"]#)'", [ '(*)' ]) = '<-> ]] ||
        die "Can't determine what getopt_long call $cmd does"
    
      short_opts=() long_opts=()
      : ${match[1]//(#m)?:#/${short_opts[1+$#short_opts]::=$MATCH}}
      : ${match[2]//(#b)'{ "'([^\"]#)'", '(<->)' }'/${long_opts[1+$#long_opts]::=$match[1]${(l($match[2])(:))}}}
      opts_with_args=(-${(M)^short_opts:#*:} --${(M)^long_opts:#*:})
      opts_with_args=(${opts_with_args%%:#})
    
      print -r -- $cmd'() {
      (
        opt=$(getopt -qo '${(j[]qq)short_opts}' '${(qq)long_opts/#/-l}' -- "$@") || exit 0
        eval "set -- $opt"
        while [ "$#" -gt 0 ]; do
          case $1 in
            (-i | --interactive | --version | --help) exit;;
            (--) printf >&2 "%s\n" "Please run '$cmd' with -i/--interactive"
                 exit 1;;
            ('${(j[ | ])${(qq)opts_with_args}}') shift;;
          esac
          shift
        done
        echo >&2 "Oops. Something when wrong"
        exit 1
      ) || return
      command '$cmd' "$@"
    }'
    done
    

    例如,在我的系统上,that-script mv rm输出:

    mv() {
      (
        opt=$(getopt -qo 'bfint:uvS:TZ' '-lbackup::' '-lcontext' '-lforce' '-linteractive' '-lno-clobber' '-lno-target-directory' '-lstrip-trailing-slashes' '-lsuffix:' '-ltarget-directory:' '-lupdate' '-lverbose' '-lhelp' '-lversion' -- "$@") || exit 0
        eval "set -- $opt"
        while [ "$#" -gt 0 ]; do
          case $1 in
        (-i | --interactive | --version | --help) exit;;
        (--) printf >&2 "%s\n" "Please run mv with -i/--interactive"
             exit 1;;
        ('-t' | '-S' | '--backup' | '--suffix' | '--target-directory') shift;;
          esac
          shift
        done
        echo >&2 "Oops. Something when wrong"
        exit 1
      ) || return
      command mv "$@"
    }
    rm() {
      (
        opt=$(getopt -qo 'dfirvIR' '-lforce' '-linteractive::' '-lone-file-system' '-lno-preserve-root' '-lpreserve-root::' '-l-presume-input-tty' '-lrecursive' '-ldir' '-lverbose' '-lhelp' '-lversion' -- "$@") || exit 0
        eval "set -- $opt"
        while [ "$#" -gt 0 ]; do
          case $1 in
        (-i | --interactive | --version | --help) exit;;
        (--) printf >&2 "%s\n" "Please run rm with -i/--interactive"
             exit 1;;
        ('--interactive' | '--preserve-root') shift;;
          esac
          shift
        done
        echo >&2 "Oops. Something when wrong"
        exit 1
      ) || return
      command rm "$@"
    }
    

    你会这样做:

    eval "$(that-script mv rm)"
    

    在您的 shell 的交互模式配置中 ( ~/.zshrc, ~/.bashrc...)。

    定义那些包装器。接着:

    $ rm a -i
    rm: remove regular file 'a'? n
    $ rm a --int
    rm: remove regular file 'a'? n
    $ mv --version
    mv (GNU coreutils) 8.32
    Copyright (C) 2020 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>.
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.
    
    Written by Mike Parker, David MacKenzie, and Jim Meyering.
    $ POSIXLY_CORRECT=1 rm a -i
    Please run rm with -i/--interactive
    
    • 1

相关问题

  • 打印文件行及其长度的脚本[关闭]

  • 通过命令的标准输出以编程方式导出环境变量[重复]

  • 按分隔符拆分并连接字符串问题

  • 如何将带有〜的路径保存到变量中?

  • MySQL Select with function IN () with bash array

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    模块 i915 可能缺少固件 /lib/firmware/i915/*

    • 3 个回答
  • Marko Smith

    无法获取 jessie backports 存储库

    • 4 个回答
  • Marko Smith

    如何将 GPG 私钥和公钥导出到文件

    • 4 个回答
  • Marko Smith

    我们如何运行存储在变量中的命令?

    • 5 个回答
  • Marko Smith

    如何配置 systemd-resolved 和 systemd-networkd 以使用本地 DNS 服务器来解析本地域和远程 DNS 服务器来解析远程域?

    • 3 个回答
  • Marko Smith

    dist-upgrade 后 Kali Linux 中的 apt-get update 错误 [重复]

    • 2 个回答
  • Marko Smith

    如何从 systemctl 服务日志中查看最新的 x 行

    • 5 个回答
  • Marko Smith

    Nano - 跳转到文件末尾

    • 8 个回答
  • Marko Smith

    grub 错误:你需要先加载内核

    • 4 个回答
  • Marko Smith

    如何下载软件包而不是使用 apt-get 命令安装它?

    • 7 个回答
  • Martin Hope
    user12345 无法获取 jessie backports 存储库 2019-03-27 04:39:28 +0800 CST
  • Martin Hope
    Carl 为什么大多数 systemd 示例都包含 WantedBy=multi-user.target? 2019-03-15 11:49:25 +0800 CST
  • Martin Hope
    rocky 如何将 GPG 私钥和公钥导出到文件 2018-11-16 05:36:15 +0800 CST
  • Martin Hope
    Evan Carroll systemctl 状态显示:“状态:降级” 2018-06-03 18:48:17 +0800 CST
  • Martin Hope
    Tim 我们如何运行存储在变量中的命令? 2018-05-21 04:46:29 +0800 CST
  • Martin Hope
    Ankur S 为什么 /dev/null 是一个文件?为什么它的功能不作为一个简单的程序来实现? 2018-04-17 07:28:04 +0800 CST
  • Martin Hope
    user3191334 如何从 systemctl 服务日志中查看最新的 x 行 2018-02-07 00:14:16 +0800 CST
  • Martin Hope
    Marko Pacak Nano - 跳转到文件末尾 2018-02-01 01:53:03 +0800 CST
  • Martin Hope
    Kidburla 为什么真假这么大? 2018-01-26 12:14:47 +0800 CST
  • Martin Hope
    Christos Baziotis 在一个巨大的(70GB)、一行、文本文件中替换字符串 2017-12-30 06:58:33 +0800 CST

热门标签

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve