When executing commands via su
as another user, the system attempts to spawn the target user's configured shell (from /etc/passwd
) before running the command. This becomes problematic when:
su - -c 'mkdir bin' user1
# Fails with: su: /usr/bin/ksh: No such file or directory
Option 1: Force bash/sh Execution
Override the shell temporarily using env
:
su - user1 -s /bin/sh -c 'mkdir bin'
# Or for more complex commands:
su - user1 -s /bin/bash -c 'export PATH=/usr/local/bin:$PATH; mkdir bin'
Option 2: Direct Command Execution
Use sudo
(if available) to bypass shell entirely:
sudo -u user1 mkdir bin
Option 3: Permanent Fix
Change the user's shell configuration:
# As root:
chsh -s /bin/bash user1
# Or edit /etc/passwd directly
The su
command behavior stems from Linux PAM (Pluggable Authentication Modules) configuration. You can examine the exact flow using:
strace -f su - user1 -c "echo test" 2>&1 | grep execve
This reveals the exact shell execution attempt before command processing.
For automation scripts, consider these robust approaches:
# Using sudo with full path
sudo -u user1 /bin/bash -c 'mkdir -p /home/user1/bin'
# Or with environment preservation
sudo -u user1 -i -- env PATH=$PATH /bin/sh -c 'complex_command'
Remember that some systems may have SELinux or AppArmor policies that affect shell switching behavior.
For system administrators managing multiple users:
# Batch change shells for users with missing shells
getent passwd | grep '/usr/bin/ksh' | cut -d: -f1 | while read user; do
chsh -s /bin/bash "$user"
done
When executing commands with su
while specifying another user, the system attempts to use the target user's default shell (as defined in /etc/passwd
). This becomes problematic when:
- The specified shell isn't installed (
ksh
in your case) - The shell exists but isn't functional
- You need to bypass shell-specific initialization files
The most straightforward method is using the --shell
parameter (GNU coreutils implementation):
su - --shell=/bin/bash -c 'mkdir bin' user1
This forces the system to use /bin/bash
regardless of the user's default shell setting.
If you have sudo privileges, this completely bypasses the shell issue:
sudo -u user1 mkdir bin
Benefits include:
- No shell switching occurs
- Cleaner process inheritance
- Better audit logging
For systems without GNU coreutils:
su - user1 -c 'exec /bin/bash -c "mkdir bin"'
For recurring issues, consider modifying /etc/default/su
(Debian) or equivalent:
# Force fallback shell
ALWAYS_SET_PATH=yes
SHELL=/bin/bash
When debugging shell issues:
# Verify user's shell setting
getent passwd user1 | cut -d: -f7
# Test shell availability
which ksh bash sh
Be aware that shell forcing may:
- Bypass security profiles (like rbash restrictions)
- Skip important environment initialization
- Affect expected PATH resolution