I have a number of folders, each with audio files in it. I want to pick out 30% of each of this files and cut them (not copy) to another folder. I can see this post which can help me do this given that I know the number of files in each folder. Sadly the number may change and I want a single piped bash line that can do this. Is this possible? How do I choose 30% of the files and cut them to another folder?
Asked
Active
Viewed 1,021 times
2 Answers
5
With bash 4.4+ and on a GNU system, you can do:
readarray -td '' files < <(
shopt -s nullglob dotglob
printf '%s\0' * | sort -Rz
)
to populate the $files array with a shuffled list of all the files in the current directory.
Then you can move 30% of them with something like:
echo mv -- "${files[@]:0:${#files[@]}*30/100}" /target/directory/
(remove the echo when you're satisfied it's going to do what you want).
The equivalent in the zsh shell could be something like:
files=(*(NDnoe['REPLY=$RANDOM']))
echo mv -- $files[1,$#files*30/100] /target/directory/
That's the same approach, only terser and not needing external utilities. Translation:
shopt -s nullglob->Nglob qualifier (create an empty array when there's no file).shopt -s dotglob->Dglob qualifier (do not exclude files whose name start with a dot).- GNU
sort -Rz:noe['REPLY=$RANDOM'](shuffle the list by sorting using a random order). ${array[@]:offset:length}->$array[first,last](zsh now also supports the Korn shell syntax, but I find the zsh one more legible).- With
bashwe use NUL delimited records (-d ''/-z/\0) to be able to deal with arbitrary file names. It's not needed inzshas the list is never transformed to a single string/stream.
Stéphane Chazelas
- 522,931
- 91
- 1,010
- 1,501
1
ls | shuf -n $(( $(ls | wc -l) * 30 / 100))
All you need to do is to find the number of files and the percentage separately. For this
$(ls | wc -l)will first calculate the number of files in the directory$(( x * 30 /100))will do the arithmetic operation of finding the 30% of that number- Finally , that number is passed to
shuf -nto get a random list of files
amisax
- 2,957
- 17
- 23
-
2`ls | wc -l` will count the number of lines returned from `ls`, which may be the same as the number of files if no filename contains any newlines. Use `set -- *; echo "$#"` to count the number of names that `*` expands to instead. – Kusalananda Sep 23 '19 at 10:22
-
or you can use `ls -b` instead – αғsнιη Sep 23 '19 at 10:44