rm, cp, mv 명령에 대한 인수 목록이 너무 김 오류
UNIX의 디렉토리 아래에 수백 개의 PDF가 있습니다. PDF의 이름이 정말 깁니다 (약 60 자).
다음 명령을 사용하여 모든 PDF를 함께 삭제하려고 할 때 :
rm -f *.pdf
다음과 같은 오류가 발생합니다.
/bin/rm: cannot execute [Argument list too long]
이 오류에 대한 해결책은 무엇입니까? 이 오류가 mv
및 cp
명령에서도 발생합니까 ? 그렇다면 이러한 명령을 해결하는 방법은 무엇입니까?
이것이 발생하는 이유는 bash가 실제로 별표를 일치하는 모든 파일로 확장하여 매우 긴 명령 줄을 생성하기 때문입니다.
이 시도:
find . -name "*.pdf" -print0 | xargs -0 rm
경고 : 이것은 재귀 검색이며 하위 디렉터리에서도 파일을 찾고 삭제합니다. 압정 -f
당신은 당신이 확인을하지 않을 경우에만 rm 명령에.
다음을 수행하여 명령을 비재 귀적으로 만들 수 있습니다.
find . -maxdepth 1 -name "*.pdf" -print0 | xargs -0 rm
또 다른 옵션은 find의 -delete
플래그 를 사용하는 것입니다 .
find . -name "*.pdf" -delete
tl; dr
명령 줄 인수의 크기에 대한 커널 제한입니다. for
대신 루프를 사용하십시오 .
문제의 기원
이것은 관련된 시스템 문제입니다 execve
및 ARG_MAX
정수입니다. 이에 대한 많은 문서가 있습니다 ( man execve , debian 's wiki 참조 ).
기본적으로 확장 은 한계 를 초과 하는 명령 (파라미터 포함)을 생성합니다 ARG_MAX
. 커널 2.6.23
에서 제한은로 설정되었습니다 128 kB
. 이 상수가 증가했으며 다음을 실행하여 값을 얻을 수 있습니다.
getconf ARG_MAX
# 2097152 # on 3.5.0-40-generic
솔루션 : for
루프 사용
BashFAQ / 095for
에서 권장 하는 루프를 사용 하고 RAM / 메모리 공간을 제외하고 제한이 없습니다.
for f in *.pdf; do rm "$f"; done
또한 glob은 셸간에 강력하고 일관된 동작을 갖기 때문에 이식 가능한 접근 방식 입니다 (POSIX 사양의 일부 ).
참고 : 여러 의견에서 언급했듯이 이것은 실제로 더 느리지 만 유지 관리가 더 용이합니다. 예를 들어 하나 이상의 작업을 수행하려는 경우 와 같이 더 복잡한 시나리오를 적용 할 수 있기 때문 입니다.
솔루션 : 사용 find
당신이 주장한다면, "NUL로 구분되지 않은 입력을 읽을 때 위험하다 (파손, 악용 가능 등)" 때문에 xargs 를 사용할 수는 find
있지만 실제로 는 사용하지 마십시오 .
find . -maxdepth 1 -name '*.pdf' -delete
사용 -maxdepth 1 ... -delete
대신하는 것은 -exec rm {} +
허용 find
단순히 때문에 빠르고, 외부 프로세스를 사용하지 않고 (덕분에 필요한 시스템 호출 자체를 실행하는 @chepner 주석 ).
참고 문헌
- "인수 목록이 너무 깁니다"라는 메시지가 나타납니다. 큰 목록을 청크로 처리하려면 어떻게해야합니까? @ 울 엣지
- execve (2)-Linux man 페이지 (ARG_MAX 검색);
- 오류 : 인수 목록이 너무 깁니다 @ Debian 's wiki;
- 인용 된 인수를 전달할 때 "/ bin / sh : 인수 목록이 너무 깁니다"라는 메시지가 나타나는 이유는 무엇입니까? @ 수퍼 유저
find
이 -delete
조치를 :
find . -maxdepth 1 -name '*.pdf' -delete
또 다른 대답은 xargs
명령을 일괄 처리 하도록 강제 하는 것입니다. 예를 들어 한 번에 delete
파일 100
로 cd
디렉토리로 이동하여 다음을 실행하십시오.
echo *.pdf | xargs -n 100 rm
또는 시도해 볼 수 있습니다.
find . -name '*.pdf' -exec rm -f {} \;
한 번에 매우 많은 파일을 삭제하려는 경우 (오늘 485,000 개 이상의 디렉토리를 삭제했습니다) 다음 오류가 발생할 수 있습니다.
/bin/rm: Argument list too long.
문제는 당신이 무언가 같이 입력 할 때이다 rm -rf *
의는 *
"RF RM은 파일 1 파일 2 파일 3 file4"등등과 같은 모든 일치하는 파일의 목록으로 대체됩니다. 이 인수 목록을 저장하는 데 할당 된 상대적으로 작은 메모리 버퍼가 있으며, 이것이 채워지면 쉘은 프로그램을 실행하지 않습니다.
이 문제를 해결하기 위해 많은 사람들이 find 명령을 사용하여 모든 파일을 찾고 다음과 같이 "rm"명령에 하나씩 전달합니다.
find . -type f -exec rm -v {} \;
내 문제는 500,000 개의 파일을 삭제해야하는데 너무 오래 걸린다는 것입니다.
파일을 삭제하는 훨씬 빠른 방법을 발견했습니다. "find"명령에는 "-delete"플래그가 내장되어 있습니다! 내가 사용한 결과는 다음과 같습니다.
find . -type f -delete
이 방법을 사용하여 초당 약 2000 개의 파일을 삭제하는 속도가 훨씬 빨라졌습니다!
삭제할 때 파일 이름을 표시 할 수도 있습니다.
find . -type f -print -delete
… 또는 삭제할 파일 수를 표시 한 다음 삭제하는 데 걸리는 시간을 표시합니다.
root@devel# ls -1 | wc -l && time find . -type f -delete
100000
real 0m3.660s
user 0m0.036s
sys 0m0.552s
당신은 이것을 시도 할 수 있습니다 :
for f in *.pdf
do
rm $f
done
편집 : ThiefMaster 의견은 어린 쉘의 jedis에게 그러한 위험한 관행을 공개하지 말 것을 제안하므로, "-rf. ..pdf"파일이있을 때 사물을 보존하기 위해 더 "안전한"버전을 추가하겠습니다.
echo "# Whooooo" > /tmp/dummy.sh
for f in '*.pdf'
do
echo "rm -i $f" >> /tmp/dummy.sh
done
위를 실행 한 후 즐겨 찾기에서 /tmp/dummy.sh 파일을 엽니 다. 편집하고 위험한 파일 이름이 있는지 모든 행을 확인하고 발견되면 주석 처리하십시오.
그런 다음 작업 디렉토리에 dummy.sh 스크립트를 복사하고 실행하십시오.
이 모든 것은 보안상의 이유입니다.
이 칭찬을 사용할 수 있습니다
find -name "*.pdf" -delete
bash 배열을 사용할 수 있습니다.
files=(*.pdf)
for((I=0;I<${#files[@]};I+=1000)); do
rm -f "${files[@]:I:1000}"
done
이렇게하면 단계 당 1000 개의 파일이 일괄 적으로 삭제됩니다.
은 rm 명령을 동시에 제거 할 수있는 파일의 제한이 있습니다.
One possibility you can remove them using multiple times the rm command bases on your file patterns, like:
rm -f A*.pdf
rm -f B*.pdf
rm -f C*.pdf
...
rm -f *.pdf
You can also remove them through the find command:
find . -name "*.pdf" -exec rm {} \;
If they are filenames with spaces or special characters, use:
find -maxdepth 1 -name '*.pdf' -exec rm "{}" \;
This sentence search all files in the current directory (-maxdepth 1) with extension pdf (-name '*.pdf'), and then, delete each one (-exec rm "{}").
The expression {} replace the name of the file, and, "{}" set the filename as string, including spaces or special characters.
i was facing same problem while copying form source directory to destination
source directory had files ~3 lakcs
i used cp with option -r and it's worked for me
cp -r abc/ def/
it will copy all files from abc to def without giving warning of Argument list too long
find . -type f -name '*xxx' -print -delete
I'm surprised there are no ulimit
answers here. Every time I have this problem I end up here or here. I understand this solution has limitations but ulimit -s 65536
seems to often do the trick for me.
I ran into this problem a few times. Many of the solutions will run the rm
command for each individual file that needs to be deleted. This is very inefficient:
find . -name "*.pdf" -print0 | xargs -0 rm -rf
I ended up writing a python script to delete the files based on the first 4 characters in the file-name:
import os
filedir = '/tmp/' #The directory you wish to run rm on
filelist = (os.listdir(filedir)) #gets listing of all files in the specified dir
newlist = [] #Makes a blank list named newlist
for i in filelist:
if str((i)[:4]) not in newlist: #This makes sure that the elements are unique for newlist
newlist.append((i)[:4]) #This takes only the first 4 charcters of the folder/filename and appends it to newlist
for i in newlist:
if 'tmp' in i: #If statment to look for tmp in the filename/dirname
print ('Running command rm -rf '+str(filedir)+str(i)+'* : File Count: '+str(len(os.listdir(filedir)))) #Prints the command to be run and a total file count
os.system('rm -rf '+str(filedir)+str(i)+'*') #Actual shell command
print ('DONE')
This worked very well for me. I was able to clear out over 2 million temp files in a folder in about 15 minutes. I commented the tar out of the little bit of code so anyone with minimal to no python knowledge can manipulate this code.
And another one:
cd /path/to/pdf
printf "%s\0" *.[Pp][Dd][Ff] | xargs -0 rm
printf
is a shell builtin, and as far as I know it's always been as such. Now given that printf
is not a shell command (but a builtin), it's not subject to "argument list too long ...
" fatal error.
So we can safely use it with shell globbing patterns such as *.[Pp][Dd][Ff]
, then we pipe its output to remove (rm
) command, through xargs
, which makes sure it fits enough file names in the command line so as not to fail the rm
command, which is a shell command.
The \0
in printf
serves as a null separator for the file names wich are then processed by xargs
command, using it (-0
) as a separator, so rm
does not fail when there are white spaces or other special characters in the file names.
I only know a way around this. The idea is to export that list of pdf files you have into a file. Then split that file into several parts. Then remove pdf files listed in each part.
ls | grep .pdf > list.txt
wc -l list.txt
wc -l is to count how many line the list.txt contains. When you have the idea of how long it is, you can decide to split it in half, forth or something. Using split -l command For example, split it in 600 lines each.
split -l 600 list.txt
this will create a few file named xaa,xab,xac and so on depends on how you split it. Now to "import" each list in those file into command rm, use this:
rm $(<xaa)
rm $(<xab)
rm $(<xac)
Sorry for my bad english.
Try this also If you wanna delete above 30/90 days (+) or else below 30/90(-) days files/folders then you can use the below ex commands
Ex: For 90days excludes above after 90days files/folders deletes, it means 91,92....100 days
find <path> -type f -mtime +90 -exec rm -rf {} \;
Ex: For only latest 30days files that you wanna delete then use the below command (-)
find <path> -type f -mtime -30 -exec rm -rf {} \;
If you wanna giz the files for more than 2 days files
find <path> -type f -mtime +2 -exec gzip {} \;
If you wanna see the files/folders only from past one month . Ex:
find <path> -type f -mtime -30 -exec ls -lrt {} \;
Above 30days more only then list the files/folders Ex:
find <path> -type f -mtime +30 -exec ls -lrt {} \;
find /opt/app/logs -type f -mtime +30 -exec ls -lrt {} \;
You can create a temp folder, move all the files and sub-folders you want to keep into the temp folder then delete the old folder and rename the temp folder to the old folder try this example until you are confident to do it live:
mkdir testit
cd testit
mkdir big_folder tmp_folder
touch big_folder/file1.pdf
touch big_folder/file2.pdf
mv big_folder/file1,pdf tmp_folder/
rm -r big_folder
mv tmp_folder big_folder
the rm -r big_folder
will remove all files in the big_folder
no matter how many. You just have to be super careful you first have all the files/folders you want to keep, in this case it was file1.pdf
To delete all *.pdf
in a directory /path/to/dir_with_pdf_files/
mkdir empty_dir # Create temp empty dir
rsync -avh --delete --include '*.pdf' empty_dir/ /path/to/dir_with_pdf_files/
To delete specific files via rsync
using wildcard is probably the fastest solution in case you've millions of files. And it will take care of error you're getting.
(Optional Step): DRY RUN. To check what will be deleted without deleting. `
rsync -avhn --delete --include '*.pdf' empty_dir/ /path/to/dir_with_pdf_files/
. . .
Click rsync tips and tricks for more rsync hacks
If you need to keep a server or system responsive while deleting a huge amount of files, sleep
between each delete statement can be a good approach.
find . -name "*.pdf" -print0 | while read -d $'\0' file
do
rm "$file"
sleep 0.005 # Sleeps for 5ms, tweak as needed
done
I found that for extremely large lists of files (>1e6), these answers were too slow. Here is a solution using parallel processing in python. I know, I know, this isn't linux... but nothing else here worked.
(This saved me hours)
# delete files
import os as os
import glob
import multiprocessing as mp
directory = r'your/directory'
os.chdir(directory)
files_names = [i for i in glob.glob('*.{}'.format('pdf'))]
# report errors from pool
def callback_error(result):
print('error', result)
# delete file using system command
def delete_files(file_name):
os.system('rm -rf ' + file_name)
pool = mp.Pool(12)
# or use pool = mp.Pool(mp.cpu_count())
if __name__ == '__main__':
for file_name in files_names:
print(file_name)
pool.apply_async(delete_files,[file_name], error_callback=callback_error)
I have faced a similar problem when there were millions of useless log files created by an application which filled up all inodes. I resorted to "locate", got all the files "located"d into a text file and then removed them one by one. Took a while but did the job!
Suppose input directory name is input and output directory name is output. Then you can use simple loop to copy all
for f in input/*
do
cp $f output
done
I had the same problem with a folder full of temporary images that was growing day by day and this command helped me to clear the folder
find . -name "*.png" -mtime +50 -exec rm {} \;
The difference with the other commands is the mtime parameter that will take only the files older than X days (in the example 50 days)
Using that multiple times, decreasing on every execution the day range, I was able to remove all the unnecessary files
If you have similar problems with grep, the easiest solution is stepping one dir back and do a recursive search.
So instead of
grep "something" *
you can use:
cd ..
grep "something" -R search_in_this_dir/
Note it will recursively search subfolders of "search_in_this_dir" directory as well.
A bit safer version than using xargs, also not recursive: ls -p | grep -v '/$' | grep '\.pdf$' | while read file; do rm "$file"; done
Filtering our directories here is a bit unnecessary as 'rm' won't delete it anyway, and it can be removed for simplicity, but why run something that will definitely return error?
Using GNU parallel (sudo apt install parallel
) is super easy
It runs the commands multithreaded where '{}' is the argument passed
E.g.
ls /tmp/myfiles* | parallel 'rm {}'
For remove first 100 files:
rm -rf 'ls | head -100'
The below option seems simple to this problem. I got this info from some other thread but it helped me.
for file in /usr/op/data/Software/temp/application/openpages-storage/*; do
cp "$file" /opt/sw/op-storage/
done
Just run the above one command and it will do the task.
참고URL : https://stackoverflow.com/questions/11289551/argument-list-too-long-error-for-rm-cp-mv-commands
'your programing' 카테고리의 다른 글
C #에서 문자열을 바이트 배열로 변환 (0) | 2020.10.03 |
---|---|
잡아 당긴 텍스트를 Vim 명령 줄에 붙여 넣는 방법은 무엇입니까? (0) | 2020.10.03 |
Git에서 SHA 해시로 커밋으로 되 돌리시겠습니까? (0) | 2020.10.03 |
디버그 빌드 전용 Visual Studio 빌드 후 이벤트를 실행하는 방법 (0) | 2020.10.03 |
Notepad ++에서 중복 행 제거 (0) | 2020.10.03 |