我是谁真的尝试执行此操作时,它会验证外部驱动器上的数据是否仍然可读。我认为最简单、最可靠的方法是将所有内容复制到/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.sh
bash 脚本。第一部分显示了 上的短时间运行(40 分钟!)的结果/home/rick/
。第二部分显示了 上的进度显示/
:
在我的系统上,有许多分区(包括两个完整的 Windows 10 安装),所有文件都在其中被读取。
catall.sh
bash 脚本
必须使用权限调用 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
它将通过键盘快捷键或启动应用程序运行。