I would like to find files whose name has only 4 characters.
Example, there are three files under /tmp
:
$ ls /tmp
txt
file
linux
Output should only show file
because it only has 4 characters.
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. It only takes a minute to sign up.
Sign up to join this communityUse the ?
wildcard for file globbing:
ls -d /tmp/????
This will print all files and directories whose filename is 4-char long.
As suggested by @roaima, the -d
flag will prevent ls
to display the content of subdirectories that match the pattern.
List files in /tmp
only:
cd /tmp
find . ! -name . -prune -path './????' -type f
List files in /tmp
recursively:
find /tmp -path '*/????' -type f
Try:
find /tmp -type f -print| awk -F/ ' length($NF) == 4 '
What awk
does:
/
as field separator, $NF
(last field)length
This seems to me like the most straightforward way to find a file of four bytes:
find /tmp -type f -size 4c
Edit: to find a file name of four bytes:
find /tmp -type f -name '????'
/tmp/somelongpathname/fred
, which doesn't match the glob /tmp/????
-maxdepth
arg to restrict to immediate entries of /tmp
. The original question is unclear on the requirement.
Jun 5, 2015 at 15:03
There's also a perl
(5.10 or newer) solution:
perl -E 'say for </tmp/????>;'
A slightly more flexible version where you can specify the desired length:
perl -E 'my $w = "?" x shift; say for </tmp/$w>;' 4
Assuming you're using bash, you can do the following:
shopt -s globstar
shopt -s nullglob
filearray=(/tmp/**/????)
This will put the list of files you want in an array filearray
. Newlines (and other exotic characters) in the filename will be handled correctly.
Setting globstar enables **
in glob patterns to match across subdirectories, giving the required recursive search.
Setting nullglob simply causes the expansion to expand to nothing if there are no matches. Otherwise it will expand to itself which is probably not what you want.
"/tmp/" takes 5 characters. That's why there is "9" (5+4) in test
for i in /tmp/* ;
do [ "${#i}" -eq 9 ] && printf %s\\n "$i";
done
or
for i in /tmp/* ;
do i="${i#/tmp/}"; # to get rid of /tmp/
[[ "${#i}" -eq 4 ]] && printf %s\\n "$i"; # there is 4 in test!
done
FWIW. It does not fail on newline (@cuonglm), can be easilly converted to list only 140 character long file names (@don_crissti).
As globbing is done by the shell, there is even no need to call ls or find, echo does the trick:
$ echo /tmp/????
/tmp/file
$
Only thing is, if there is no file whose name is 4 characters long, it will just print
/tmp/????
You might want a one-liner bash script that checks this and also prints one file per line:
pattern=/tmp/????? ; for f in $pattern ; do if [ $f != "$pattern" ] ; then echo $f ; fi ; done
How about:
ls /tmp | grep -e '^.\{4\}$'
for a grep
based answer.
ls -q | grep -E '^.{4}$'
should take care of those file names with funky chars (though they'll appear as question marks in the output).
Jun 5, 2015 at 9:46
echo /tmp/{.,?}???
.grep
based solution yet?grep
matches lines of text, but not all filenames are guaranteed to be single lines of text.beta
in UTF-8 is 4 characters and 4 bytes long, whilebétá
is 4 characters and 6 bytes....