尝试将目录 CP 到 /dev/null

尝试将目录 CP 到 /dev/null

我是谁真的尝试执行此操作时,它会验证外部驱动器上的数据是否仍然可读。我认为最简单、最可靠的方法是将所有内容复制到/dev/null。它对文件非常有效。但是当我将-R递归复制添加到目录结构时,如果失败(大概),因为它无法在中创建子目录/dev/null

当我尝试时:

cp -R Flintstones/ /dev/null

我得到:

cp: cannot overwrite non-directory '/dev/null' with directory 'Flintstones/'

但这有效:

cd Flintstones
cp Fred.txt /dev/null

我怎样才能一次性复制整个目录?

谢谢你,请温柔地对待新手。

答案1

我找到了一种替代 rsync 的好方法,用于读取硬盘而无需复制。

在 bash 窗口 #1 中运行以下命令:

tar -cv <path to your hard disk> 2>/tmp/tt |pv >/dev/null

以字节 / MB / GB 为单位显示进度以及当前传输速度,例如:

$ sudo tar -cv /mnt/mnt/ 2>/tmp/tt |pv >/dev/null 
111GiB 0:21:57 [99,0MiB/s] [                 <=>                          ]

在 bash 窗口 #2 中运行此命令以显示当前正在读取的文件(测试完成后使用 ctrl-c 终止)。

tail -f /tmp/tt

即使您的硬盘包含块设备描述符等特殊文件,这也能起作用。

背景:tar -cv <dirname> 创建一个包含 <dirname> 中所有文件的存档。输出通过管道(“|”),文件名打印到 stderr,然后重定向到 /tmp/tt。pv 打印出大小和当前传输速度。使用选项“-s”,您可以告诉 pv 您的数据有多大(例如“pv -s 370G”),因此它还可以打印出已复制的数据百分比:

$ sudo tar -cv /media/jcs/SG4TBR1/ 2>/tmp/tt |pv -s370G >/dev/null 
24,7GiB 0:04:07 [ 130MiB/s] [=>                   ]  6% ETA 0:57:27

“tail -f /tmp/tt” 只是打印 /tmp/tt 的内容并继续显示任何变化(-f:“follow”)。

答案2

您好,欢迎来到 Ask Ubuntu!

如果我正确理解了您的问题,您只想运行一些命令来读取给定目录中的所有文件,但除了潜在的错误消息“无法读取文件”之外,您对任何输出都不感兴趣。例如,您可以使用grep以下命令实现这一点:

grep -r Zaphod Flintstones/

上述命令意味着grep将递归遍历Flintstones目录中的所有文件,查找字符串“Zaphod”(您可以在此处输入其他字符串,这无关紧要,只需输入要grep搜索的内容即可,如果您不希望输出任何内容,请选择您认为不会出现在任何文件中的内容)。如果命令完成时没有出现有关不可读文件的错误消息,则表示目录可读。

并不是说这是最好的方法,可能还有更优雅的方法,但上述方法是一种。

答案3

使用cat而不是cp

您可以使用命令,而不必cp读取每个文件cat

下面的屏幕演示了catall.shbash 脚本。第一部分显示了 上的短时间运行(40 分钟!)的结果/home/rick/。第二部分显示了 上的进度显示/

目录进度显示.gif

在我的系统上,有许多分区(包括两个完整的 Windows 10 安装),所有文件都在其中被读取。

catall.shbash 脚本

必须使用权限调用 bash 脚本,sudo因为 Linux 中有些文件普通用户无法读取。此外,您必须将参数传递给起始位置才能开始读取文件,例如//mnt/ext_drive等:

#!/bin/bash

# NAME: catall.sh (cat every single file)
# PATH: $HOME/askubuntu/
# DESC: Answer for: https://askubuntu.com/questions/1184103/trying-to-cp-a-directory-to-dev-null/1184105#1184105
# DATE: October 27, 2019.

[[ $(id -u) != 0 ]] && { echo "Must be called with sudo" >&2 ; exit 2 ; }
[[ $1 != /* ]] && { echo "Parameter 1 must be a path" >&2 ; exit 3 ; }


DirCnt=0    # Directory count
FileCnt=0   # File
LinkCnt=0   # Symbolic Link
BdevCnt=0   # Block Device
CdevCnt=0   # Character Device
PipeCnt=0   # Pipe
SockCnt=0   # Socket
ZeroCnt=0   # Zero sized files count
SkipCnt=0   # Files skipped

updatedb    # Update locate's database for files added today
StartSec=$SECONDS

while read File ; do
    if [[ ! -e "$File" ]] ; then : # File no longer exists, stale database
    elif [[ -d "$File" ]] ; then (( DirCnt++ ))
    elif [[ -h "$File" ]] ; then (( LinkCnt++ ))
    elif [[ -b "$File" ]] ; then (( BdevCnt++ ))
    elif [[ -b "$File" ]] ; then (( CdevCnt++ ))
    elif [[ -c "$File" ]] ; then (( CdevCnt++ ))
    elif [[ -p "$File" ]] ; then (( PipeCnt++ ))
    elif [[ -S "$File" ]] ; then (( SockCnt++ ))
    # elif [[ $File == /mnt/* ]] ; then (( SkipCnt ++ ))
    elif [[ -s "$File" ]] ; then
        cat "$File" 1>/dev/null
        (( FileCnt++ ))
    else
        (( ZeroCnt++ ))
    fi
    printf "Number of Directories: %'d Files: %'d \r" "$DirCnt" "$FileCnt"
done <<<"$(locate "$1")"

echo # Line feed to keep statistics visible when job ends
printf "Number of Sybolic Links: %'d\n"     "$LinkCnt"
printf "Number of Block Devices: %'d\n"     "$BdevCnt"
printf "Number of Character Devices: %'d\n" "$CdevCnt"
printf "Number of Pipes: %'d\n"             "$PipeCnt"
printf "Number of Sockets: %'d\n"           "$SockCnt"
printf "Number of Zero sized files: %'d\n"  "$ZeroCnt"
# printf "Number of Skipped files: %'d\n"     "$SkipCnt"
echo
EndSec=$SECONDS
TotalSec=$(( EndSec - StartSec ))
printf "Total Seconds: %'d\n"               "$TotalSec"

注释掉两行以跳过特定目录:

    # elif [[ $File == /mnt/* ]] ; then (( SkipCnt ++ ))
# printf "Number of Skipped files: %'d\n"     "$SkipCnt"

删除注释标记 ( #) 并切换/mnt/*到您想要跳过的目录以节省时间。 在我的例子中,/mnt/代表不同分区上的 Windows 和其他 Ubuntu 安装中的一百万个文件。


速度cat太恐怖了

最终结果是:

$ sudo ./catall.sh /

Number of Directories: 378,571 Files: 1,741,640 
Number of Sybolic Links: 92,011
Number of Block Devices: 25
Number of Character Devices: 55
Number of Pipes: 48
Number of Sockets: 138
Number of Zero sized files: 210,515

Total Seconds: 82,554

这个过程耗时23个小时,几乎一整天!

dd即使读取整个分区(包括不存在文件的空间),也可以实现更快的速度:

$ time sudo dd if=/dev/nvme0n1p4 of=/dev/null bs=100M
3719+1 records in
3719+1 records out
389969573888 bytes (390 GB, 363 GiB) copied, 249.867 s, 1.6 GB/s

real    4m9.896s
user    0m0.017s
sys     2m38.305s

为什么要使用sudo脚本catall.sh

此示例说明了为什么sudo需要:

$ locate udev.log.1.gz
/mnt/clone/var/log/upstart/udev.log.1.gz
/var/log/upstart/udev.log.1.gz

$ cat /var/log/upstart/udev.log.1.gz | wc
cat: /var/log/upstart/udev.log.1.gz: Permission denied
      0       0       0

$ sudo cat /var/log/upstart/udev.log.1.gz | wc
      0       1      82

答案4

根据 WinEunuuchs2Unix 所写的内容,我对其进行了一些美化:

#!/bin/bash
# NAME: cachewarmup.sh
# DESC: Adapted from https://askubuntu.com/questions/1184103/trying-to-cp-a-directory-to-dev-null/1184105#1184105
# DATE: 25 Feb 2023

[[ $(id -u) != 0 ]] && { echo "Must be called with sudo" >&2 ; exit 2 ; }
[[ $1 != /* ]] && { echo "Input flag must be the starting directory ( sudo cachewarmup / for root directory )" >&2 ; exit 3 ; }

# NOTE: Put Omitted Paths below:
# =============================
OP0="/mnt/**/*"
OP1="/media/$USER/**/*"
OP2=""
OP3=""
OP4=""
OP5=""
OP6=""
OP7=""
OP8=""
OP9=""
# =============================

SkipCnt=0                                                                               # Count of skipped files
StalCnt=0                                                                               # Count of files that existed last run, but don't now
ZeroCnt=0                                                                               # Count of zero sized files
DirCnt=0                                                                                # Count of directories
LinkCnt=0                                                                               # Count of symbolic links
CdevCnt=0                                                                               # Count of character devices
BdevCnt=0                                                                               # Count of block devices
PipeCnt=0                                                                               # Count of pipes
SockCnt=0                                                                               # Count of sockets
FileCnt=0                                                                               # Count of files cache-loaded

StartSec=$SECONDS
clear
echo "Updating Locate's database... please wait..."
updatedb > /dev/null 2>&1                                                               # Update locate's database for recently added files
clear
tput civis
for file in $(find $1 -maxdepth 10000 -xdev -ignore_readdir_race); do
    if [[ "$file" =~ ^($OP0|$OP1|$OP2|$OP3|$OP4|$OP5|$OP6|$OP7|$OP8|$OP9)$ ]]; then (( SkipCnt++ )) # Count of skipped files
    elif [[ ! -e "$file" ]] ; then (( StalCnt++ ))                                      # Count of files that existed last run, but don't now
    elif [[ ! -s "$file" ]] ; then (( ZeroCnt++ ))                                      # Count of zero sized files
    elif [[ -d "$file" ]] ; then (( DirCnt++ ))                                         # Count of directories
    elif [[ -h "$file" || -L "$file" ]] ; then (( LinkCnt++ ))                          # Count of symbolic links
    elif [[ -c "$file" ]] ; then (( CdevCnt++ ))                                        # Count of character devices
    elif [[ -b "$file" ]] ; then (( BdevCnt++ ))                                        # Count of block devices
    elif [[ -p "$file" ]] ; then (( PipeCnt++ ))                                        # Count of pipes
    elif [[ -S "$file" ]] ; then (( SockCnt++ ))                                        # Count of sockets
    elif [[ -f "$file" && -s "$file" ]] ; then                                          # File must exist, and not be any of the above.
        cat "$file" 1>/dev/null
        (( FileCnt++ ))                                                                 # Count of files cache-loaded
    else
        (( SkipCnt++ ))                                                                 # Count of any files not otherwise processed.
    fi
    printf "  Directories:      %d\n"       "$DirCnt"
    printf "  Cached Files:     %d\n"       "$FileCnt"
    printf "  Symbolic Links:   %d\n"       "$LinkCnt"
    printf "  Block Devices:    %d\n"       "$BdevCnt"
    printf "  Character Devices:    %d\n"   "$CdevCnt"
    printf "  Pipes:        %d\n"           "$PipeCnt"
    printf "  Sockets:      %d\n"           "$SockCnt"
    printf "  Zero Sized files: %d\n"       "$ZeroCnt"
    printf "  Skipped files:    %d\n"       "$SkipCnt"
    printf "  Stale files:      %d\n"       "$StalCnt"
    echo
    tput cup 11 1;tput el;printf "%s" "$file"
    tput cup 12 0;tput el
    tput cup 13 0;tput el
    Elapsed=($SECONDS - $StartSec)
    tput cup 14 1;tput el;printf "Time %dh:%dm:%ds" "$((($Elapsed)/3600))" "$(((($Elapsed)%3600)/60))" "$((($Elapsed)%60))"
    tput cup 0 0
done <<<"$(locate "$1")"
tput cnorm

如果你想让它变得更好:

nice gnome-terminal -- /bin/sh -c 'echo Warming up ZFS ARC...; sleep 60; sudo cachewarmup /; sleep 300' 19

它将通过键盘快捷键或启动应用程序运行。

相关内容