I'm searching a way to be sure my commands are executed by bash on some FreeBSD 11 machines that use csh as default shell.

The following is my code that works on Linux CentOS / Debian / MacOS X / pfSense 2.3 (running on FreeBSD 10.3) and even Windows 10 bash, but doesn't work on FreeBSD 11

cat "/some/filelist" | ssh -i "/home/user/.ssh/some_key" user@freebsd11  'bash -c "while read -r file; do stat -f \"%N;%c;%m\" \"\$file\"; done | sort"'

Output of the previous command on FreeBSD 11 seems to be a csh error message

Unmatched ".

When checking which shell runs, it seems that csh runs. The following returns 'csh'

ssh -i /home/user/.ssh/some_key user@freebsd11 'bash -c "echo $0"'

As of my understandings, BSD systems do not allow changing shell, unless using a heredoc, but I can't send cat "/some/filelist" using a heredoc.

Of course, bash is installed and can be executed. I'm not interested in changing the default shell of the users on FreeBSD.

Any ideas here ?

My best guess would be to divide the problem:

1/ send the file with cat /some/filelist | ssh [..] 'cat > somefile'

2/ use the sent file in a heredoc

ssh [..] 'bash -s' << 'EOF'
while read -r file; do stat -f "%N;%c;%m" "$file" | sort; done < "$somefile"

This solution could work but is messy, makes 2 connections instead of one and won't work if remote can't write the 'somefile' for some reason.


If you simplify your command line, the shell likely won't matter. This should likely work

ssh </some/filelist -i /home/user/.ssh/some_key user@freebsd11 xargs -n 1 stat -f \"%N;%c;%m\" | sort

Alternatively, you may want to change the default shell to bash for the particular user you are ssh-ing to - see the chsh(1) command.

  • Nice, but not space safe. Using ssh </some/filelist -i /home/user/.ssh/some_key user@freebsd11 xargs -I {} stat -f "%N;%c;%m" "{}" | sort would render it space safe. Two questions: 1/ How portable is this ? 2/ xargs is limited in argument size. How can I deal with (very) big file list ? I can't reasonably increase ARG_MAX to a trivial value. – Orsiris de Jong Dec 9 '16 at 7:56
  • xargs runs the command multiple times to avoid limitations on maximum arguments, so can handle a list of arbitrary size. I suggested "-n 1" because I didn't know if stat behaves differently with more than one argument. – John Sellens Dec 9 '16 at 14:29
  • Yep, after some research, I mistook ARG_MAX and entry size. – Orsiris de Jong Dec 9 '16 at 18:07

Use ansible. You don't need to add any additional software on the target machines and, arguably, it simplifies what you need to do. ansible uses standard ssh to connect to the machines, sudo, pfexec or doas are available if you need to run with privileges, and you can choose which user to connect as, and which user to execute as.

If the actual task is to perform stat on a list of files, there's already a module for that, and a lookup to iterate over the lines of a file:

- hosts: freebsd11:pfsense
  gather_facts: yes

  - name: stat a list of files
    stat: "{{ item }}"
     - cat /path/to/list_of_files

If the task is an arbitrary shell command that needs to be executed in the target machine using bash, there's also a module for that:

- hosts: freebsd11:pfsense
  gather_facts: yes

  - name: execute shell script using bash
    shell: cat < /tmp/*txt
        executable: /bin/bash
  • Well yes, but, it's basically like trying to kill a fly with a bazooka. Plus, it adds python dependancy which in my user case greatly reduces portability. Still upvoting because it could work. – Orsiris de Jong Dec 9 '16 at 8:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.