Skip to main content
`find` files \0 delimited and `sort -z` and assigned to an array for use by the (main) process
Source Link
Peter.O
  • 33.7k
  • 32
  • 120
  • 167

IfIt seems that your file1 has no trailing newline. If you want to concatenate a list of files. YoucYou can first check each one and cat a newline where needed, as follows:

# make some sample files
printf "%s\n" abc > file1  
printf "%s"   def > file2  # no trailing newline
printf "%s\n" abcghi > file3
printf "%s"   defjkl > file4  # no trailing newline

# find files to concatenate and build a sorted array `f[]`
unset f i; 
while IFS= read -r -d $'\0' path; do f[i++]="$path"
done < <(find . -type f -name 'file[0-9]' -print0 | sort -z)

# build the `cat` command
cmd=cat
tmp="$(mktemp)"; echo >$tmp   # a file which contains only a `\n`
cmd=cat
for file in file1 file2 file3 file4;"${f[@]}"; do
    [[ $lasthex=$(tail -c1 $file | hexdump -ve '1/1 "%02x"')
    [[ -z $lasthex ]] && continue     # skip enpty files
    [[ $lasthex == 0a ]] && nl= || nl=" $tmp"
    cmd="$cmd \"$file\"$nl"
done

# execute the `cat` command
eval "$cmd"

The concatenated result is:

abc
def
abcghi
defjkl

The generated command is:

cat "file1""./file1" "file2""./file2" /tmp/tmp.nEdFkdWgJez7iKccY0T9 "file3""./file3" "file4""./file4" /tmp/tmp.nEdFkdWgJez7iKccY0T9

If you want to concatenate a list of files. Youc can check each one as follows:

# some sample files
printf "%s\n" abc > file1  
printf "%s"   def > file2  # no trailing newline
printf "%s\n" abc > file3
printf "%s"   def > file4  # no trailing newline

tmp="$(mktemp)"; echo >$tmp  # a file which contains only a `\n`
cmd=cat
for file in file1 file2 file3 file4; do
    [[ $(tail -c1 $file | hexdump -ve '1/1 "%02x"') == 0a ]] && nl= || nl=" $tmp"
    cmd="$cmd \"$file\"$nl"
done
eval "$cmd"

The concatenated result is:

abc
def
abc
def

The generated command is:

cat "file1" "file2" /tmp/tmp.nEdFkdWgJe "file3" "file4" /tmp/tmp.nEdFkdWgJe

It seems that your file1 has no trailing newline. If you want to concatenate a list of files. You can first check each one and cat a newline where needed, as follows:

# make some sample files
printf "%s\n" abc > file1  
printf "%s"   def > file2  # no trailing newline
printf "%s\n" ghi > file3
printf "%s"   jkl > file4  # no trailing newline

# find files to concatenate and build a sorted array `f[]`
unset f i; 
while IFS= read -r -d $'\0' path; do f[i++]="$path"
done < <(find . -type f -name 'file[0-9]' -print0 | sort -z)

# build the `cat` command
cmd=cat
tmp="$(mktemp)"; echo >$tmp   # a file which contains only `\n`
for file in "${f[@]}"; do
    lasthex=$(tail -c1 $file | hexdump -ve '1/1 "%02x"')
    [[ -z $lasthex ]] && continue     # skip enpty files
    [[ $lasthex == 0a ]] && nl= || nl=" $tmp"
    cmd="$cmd \"$file\"$nl"
done

# execute the `cat` command
eval "$cmd"

The concatenated result is:

abc
def
ghi
jkl

The generated command is:

cat "./file1" "./file2" /tmp/tmp.z7iKccY0T9 "./file3" "./file4" /tmp/tmp.z7iKccY0T9
added 36 characters in body
Source Link
Peter.O
  • 33.7k
  • 32
  • 120
  • 167

If you want to concatenate a list of files. Youc can check each one as follows:

# some sample files
printf "%s\n" abc > file1  
printf "%s"   def > file2  # no trailing newline
printf "%s\n" abc > file3
printf "%s"   def > file4  # no trailing newline
 
 

tmp="$(mktemp)"; echo >$tmp  # a file which contains only a `\n`
cmd=cat
for file in file1 file2 file3 file4; do
    [[ $(tail -c1 $file | hexdump -ve '1/1 "%02x"') == 0a ]] && nl= || nl=" $tmp"
    cmd="$cmd \"$file\"$nl"
done
eval "$cmd"

The concatenated result is:

abc
def
abc
def

The generated command is:

cat "file1" "file2" /tmp/tmp.nEdFkdWgJe "file3" "file4" /tmp/tmp.nEdFkdWgJe

If you want to concatenate a list of files. Youc can check each one as follows:

printf "%s\n" abc > file1  
printf "%s"   def > file2  # no trailing newline
printf "%s\n" abc > file3
printf "%s"   def > file4  # no trailing newline
 
tmp="$(mktemp)"; echo >$tmp
cmd=cat
for file in file1 file2 file3 file4; do
    [[ $(tail -c1 $file | hexdump -ve '1/1 "%02x"') == 0a ]] && nl= || nl=" $tmp"
    cmd="$cmd \"$file\"$nl"
done
eval "$cmd"

The concatenated result is:

abc
def
abc
def

If you want to concatenate a list of files. Youc can check each one as follows:

# some sample files
printf "%s\n" abc > file1  
printf "%s"   def > file2  # no trailing newline
printf "%s\n" abc > file3
printf "%s"   def > file4  # no trailing newline
 

tmp="$(mktemp)"; echo >$tmp  # a file which contains only a `\n`
cmd=cat
for file in file1 file2 file3 file4; do
    [[ $(tail -c1 $file | hexdump -ve '1/1 "%02x"') == 0a ]] && nl= || nl=" $tmp"
    cmd="$cmd \"$file\"$nl"
done
eval "$cmd"

The concatenated result is:

abc
def
abc
def

The generated command is:

cat "file1" "file2" /tmp/tmp.nEdFkdWgJe "file3" "file4" /tmp/tmp.nEdFkdWgJe
Source Link
Peter.O
  • 33.7k
  • 32
  • 120
  • 167

If you want to concatenate a list of files. Youc can check each one as follows:

printf "%s\n" abc > file1  
printf "%s"   def > file2  # no trailing newline
printf "%s\n" abc > file3
printf "%s"   def > file4  # no trailing newline

tmp="$(mktemp)"; echo >$tmp
cmd=cat
for file in file1 file2 file3 file4; do
    [[ $(tail -c1 $file | hexdump -ve '1/1 "%02x"') == 0a ]] && nl= || nl=" $tmp"
    cmd="$cmd \"$file\"$nl"
done
eval "$cmd"

The concatenated result is:

abc
def
abc
def